"Fossies" - the Fresh Open Source Software Archive 
Member "Pound-3.0.2/src/config.c" (28 Nov 2021, 34972 Bytes) of package /linux/www/Pound-3.0.2.tgz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "config.c" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
3.0e_vs_3.0.1.
1 /*
2 * Pound - the reverse-proxy load-balancer
3 * Copyright (C) 2002-2020 Apsis GmbH
4 *
5 * This file is part of Pound.
6 *
7 * Pound is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * Pound is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/> .
19 *
20 * Contact information:
21 * Apsis GmbH
22 * P.O.Box
23 * 8707 Uetikon am See
24 * Switzerland
25 * EMail: roseg@apsis.ch
26 */
27
28 #include "pound.h"
29
30 static UT_array *ut_backends;
31 static UT_array *ut_http;
32
33 void
34 fatal(const char *fmt, ...)
35 {
36 char buf[MAXBUF + 1];
37 va_list ap;
38
39 buf[MAXBUF] = '\0';
40 va_start(ap, fmt);
41 vsnprintf(buf, MAXBUF, fmt, ap);
42 va_end(ap);
43
44 global.log_level = 1;
45 logmsg(0, buf);
46 exit(3);
47 }
48
49 static char *
50 file2str(const char *fname)
51 {
52 char *res;
53 struct stat st;
54 FILE *fin;
55
56 if(stat(fname, &st)
57 || (fin = fopen(fname, "r")) == NULL
58 || (res = malloc(st.st_size + 1)) == NULL
59 || fread(res, 1, st.st_size, fin) != st.st_size)
60 fatal("YAML can't access file %s", fname);
61 res[st.st_size] = '\0';
62 fclose(fin);
63 return res;
64 }
65
66 static void
67 get_global(yaml_document_t *document, yaml_node_t *root)
68 {
69 yaml_node_pair_t *cur_pair;
70 yaml_node_t *node;
71 struct passwd *pwent;
72 struct group *grent;
73
74 logmsg(1, "start get_global %s:%d", __FILE__, __LINE__);
75 for(cur_pair = root->data.mapping.pairs.start; cur_pair < root->data.mapping.pairs.top; cur_pair++)
76 if(!strcasecmp("User", yaml_document_get_node(document, cur_pair->key)->data.scalar.value)) {
77 if((pwent = getpwnam(yaml_document_get_node(document, cur_pair->value)->data.scalar.value)) == NULL)
78 fatal("User %s not found", yaml_document_get_node(document, cur_pair->value)->data.scalar.value);
79 global.user = pwent->pw_uid;
80 logmsg(4, "user %d %s:%d", global.user, __FILE__, __LINE__);
81 } else if(!strcasecmp("Group", yaml_document_get_node(document, cur_pair->key)->data.scalar.value)) {
82 if((grent = getgrnam(yaml_document_get_node(document, cur_pair->value)->data.scalar.value)) == NULL)
83 fatal("Group %s not found", yaml_document_get_node(document, cur_pair->value)->data.scalar.value);
84 global.group = grent->gr_gid;
85 logmsg(4, "group %d %s:%d", global.group, __FILE__, __LINE__);
86 } else if(!strcasecmp("RootJail", yaml_document_get_node(document, cur_pair->key)->data.scalar.value)) {
87 if((global.root_jail = strdup(yaml_document_get_node(document, cur_pair->value)->data.scalar.value)) == NULL)
88 fatal("Out of memory at %ld", yaml_document_get_node(document, cur_pair->value)->start_mark.line);
89 logmsg(4, "RootJail %s %s:%d", global.root_jail, __FILE__, __LINE__);
90 } else if(!strcasecmp("Err404", yaml_document_get_node(document, cur_pair->key)->data.scalar.value)) {
91 global.err404 = file2str(yaml_document_get_node(document, cur_pair->value)->data.scalar.value);
92 logmsg(4, "err404 %s %s:%d", global.err404, __FILE__, __LINE__);
93 } else if(!strcasecmp("Err405", yaml_document_get_node(document, cur_pair->key)->data.scalar.value)) {
94 global.err405 = file2str(yaml_document_get_node(document, cur_pair->value)->data.scalar.value);
95 logmsg(4, "err405 %s %s:%d", global.err405, __FILE__, __LINE__);
96 } else if(!strcasecmp("Err500", yaml_document_get_node(document, cur_pair->key)->data.scalar.value)) {
97 global.err500 = file2str(yaml_document_get_node(document, cur_pair->value)->data.scalar.value);
98 logmsg(4, "err500 %s %s:%d", global.err500, __FILE__, __LINE__);
99 } else
100 fatal("Unknown directive %s at line %ld", yaml_document_get_node(document, cur_pair->key)->data.scalar.value,
101 yaml_document_get_node(document, cur_pair->key)->start_mark.line);
102
103 if(global.err404 == NULL)
104 global.err404 = "<html><head><title>Not Found</title></head><body><h1>Page not found</h1></body></html>\r\n";
105 if(global.err405 == NULL)
106 global.err405 = "<html><head><title>Not Allowed</title></head><body><h1>Method not allowed</h1></body></html>\r\n";
107 if(global.err500 == NULL)
108 global.err500 = "<html><head><title>Error</title></head><body><h1>Internal error</h1></body></html>\r\n";
109
110 return;
111 }
112
113 static void
114 get_backends(yaml_document_t *document, yaml_node_t *root)
115 {
116 yaml_node_pair_t *cur_pair;
117 yaml_node_t *vals;
118 yaml_node_item_t *cur;
119 BACKEND res;
120 char addr[NI_MAXHOST], port[NI_MAXSERV], redirect[NI_MAXHOST];
121 struct addrinfo hints;
122
123 logmsg(1, "start get_backends %s:%d", __FILE__, __LINE__);
124 memset(&hints, '\0', sizeof(hints));
125 hints.ai_family = AF_UNSPEC;
126 hints.ai_socktype = SOCK_STREAM;
127 for(cur = root->data.sequence.items.start; cur < root->data.sequence.items.top; cur++) {
128 memset(&res, '\0', sizeof(res));
129 res.id = *cur;
130 vals = yaml_document_get_node(document, *cur);
131 if(vals->type != YAML_MAPPING_NODE)
132 fatal("Backend at %ld: not a mapping", vals->start_mark.line);
133 addr[0] = '\0';
134 port[0] = '\0';
135 redirect[0] = '\0';
136 for(cur_pair = vals->data.mapping.pairs.start; cur_pair < vals->data.mapping.pairs.top; cur_pair++)
137 if(!strcasecmp("Address", yaml_document_get_node(document, cur_pair->key)->data.scalar.value)) {
138 strncpy(addr, yaml_document_get_node(document, cur_pair->value)->data.scalar.value, NI_MAXHOST);
139 logmsg(4, "addr %s %s:%d", addr, __FILE__, __LINE__);
140 } else if(!strcasecmp("Port", yaml_document_get_node(document, cur_pair->key)->data.scalar.value)) {
141 strncpy(port, yaml_document_get_node(document, cur_pair->value)->data.scalar.value, NI_MAXSERV);
142 logmsg(4, "port %s %s:%d", port, __FILE__, __LINE__);
143 } else if(!strcasecmp("Timeout", yaml_document_get_node(document, cur_pair->key)->data.scalar.value)) {
144 res.timeout = atoi(yaml_document_get_node(document, cur_pair->value)->data.scalar.value);
145 logmsg(4, "timeout %d %s:%d", res.timeout, __FILE__, __LINE__);
146 } else if(!strcasecmp("Threads", yaml_document_get_node(document, cur_pair->key)->data.scalar.value)) {
147 res.threads = atoi(yaml_document_get_node(document, cur_pair->value)->data.scalar.value);
148 logmsg(4, "threads %d %s:%d", res.threads, __FILE__, __LINE__);
149 } else if(!strcasecmp("HeadAdd", yaml_document_get_node(document, cur_pair->key)->data.scalar.value)) {
150 if((res.add_header = strdup(yaml_document_get_node(document, cur_pair->value)->data.scalar.value)) == NULL)
151 fatal("HeadAdd out of memory at line %ld", yaml_document_get_node(document, cur_pair->key)->start_mark.line);
152 if(strlen(res.add_header) == 0)
153 fatal("HeadAdd at line %ld: header may not be empty", yaml_document_get_node(document, cur_pair->key)->start_mark.line);
154 logmsg(4, "HeadAdd %s %s:%d", res.add_header, __FILE__, __LINE__);
155 } else
156 fatal("Unknown directive %s at line %ld", yaml_document_get_node(document, cur_pair->key)->data.scalar.value,
157 yaml_document_get_node(document, cur_pair->key)->start_mark.line);
158
159 if(addr[0]) {
160 if(res.threads <= 0)
161 res.threads = 8;
162 if(res.timeout <= 0)
163 res.timeout = 15;
164 if(getaddrinfo(addr, port, &hints, &res.addr))
165 fatal("Backend at %ld: unknown server %s:%s", vals->start_mark.line, addr, port);
166 } else
167 fatal("Backend at %ld: missing data", vals->start_mark.line);
168 logmsg(2, "push %s:%d", __FILE__, __LINE__);
169 utarray_push_back(ut_backends, &res);
170 }
171 }
172
173 static UT_array *
174 get_svc_backends(yaml_document_t *document, yaml_node_t *root)
175 {
176 yaml_node_item_t *cur;
177 UT_array *res;
178 UT_icd backend_icd = {sizeof(BACKEND *), NULL, NULL, NULL };
179 int i;
180 BACKEND *be;
181
182 if(root->type != YAML_SEQUENCE_NODE)
183 fatal("YAML Services not sequence (%ld)", root->start_mark.line);
184 utarray_new(res, &backend_icd);
185 for(cur = root->data.sequence.items.start; cur < root->data.sequence.items.top; cur++) {
186 for(i = 0; i < backends_len; i++)
187 if(backends[i].id == *cur) {
188 be = &backends[i];
189 utarray_push_back(res, &be);
190 break;
191 }
192 }
193 return res;
194 }
195
196 static UT_array *
197 get_services(yaml_document_t *document, yaml_node_t *root)
198 {
199 yaml_node_pair_t *map_pair;
200 yaml_node_item_t *cur;
201 yaml_node_t *vals;
202 UT_array *res, *bes;
203 BACKEND *be;
204 UT_icd service_icd = {sizeof(SERVICE), NULL, NULL, NULL };
205 SERVICE *svc;
206 int i;
207 char pat[MAXBUF];
208
209 logmsg(1, "start get_services %s:%d", __FILE__, __LINE__);
210 if(root->type != YAML_SEQUENCE_NODE)
211 fatal("YAML Services not sequence (%ld)", root->start_mark.line);
212 utarray_new(res, &service_icd);
213 bes = NULL;
214
215 for(cur = root->data.sequence.items.start; cur < root->data.sequence.items.top; cur++) {
216 vals = yaml_document_get_node(document, *cur);
217 if(vals->type != YAML_MAPPING_NODE)
218 fatal("Service at %ld: not a mapping", vals->start_mark.line);
219 if((svc = calloc(1, sizeof(SERVICE))) == NULL)
220 fatal("Service at %ld: out of memory", vals->start_mark.line);
221 for(map_pair = vals->data.mapping.pairs.start; map_pair < vals->data.mapping.pairs.top; map_pair++) {
222 if(!strcasecmp("URL", yaml_document_get_node(document, map_pair->key)->data.scalar.value)) {
223 if((svc->url = malloc(sizeof(regex_t))) == NULL)
224 fatal("Service at %ld: out of memory", vals->start_mark.line);
225 snprintf(pat, MAXBUF, "[^ \t]+[ \t]%s[ \t].*", yaml_document_get_node(document, map_pair->value)->data.scalar.value);
226 if(regcomp(svc->url, pat, REG_ICASE))
227 fatal("Service at %ld: bad URL pattern %s", vals->start_mark.line, pat);
228 logmsg(4, "URL %s %s:%d", yaml_document_get_node(document, map_pair->value)->data.scalar.value, __FILE__, __LINE__);
229 } else if(!strcasecmp("Session", yaml_document_get_node(document, map_pair->key)->data.scalar.value)) {
230 svc->session = atoi(yaml_document_get_node(document, map_pair->value)->data.scalar.value);
231 logmsg(4, "session %d %s:%d", svc->session, __FILE__, __LINE__);
232 } else if(!strcasecmp("HeadRequire", yaml_document_get_node(document, map_pair->key)->data.scalar.value)) {
233 if((svc->head_require = malloc(sizeof(regex_t))) == NULL)
234 fatal("Service at %ld: out of memory", vals->start_mark.line);
235 if(regcomp(svc->head_require, yaml_document_get_node(document, map_pair->value)->data.scalar.value, REG_ICASE))
236 fatal("Service at %ld: bad HeadRequire pattern %s", vals->start_mark.line, yaml_document_get_node(document, map_pair->value)->data.scalar.value);
237 logmsg(4, "HeadRequire %s %s:%d", yaml_document_get_node(document, map_pair->value)->data.scalar.value, __FILE__, __LINE__);
238 } else if(!strcasecmp("HeadDeny", yaml_document_get_node(document, map_pair->key)->data.scalar.value)) {
239 if((svc->head_deny = malloc(sizeof(regex_t))) == NULL)
240 fatal("Service at %ld: out of memory", vals->start_mark.line);
241 if(regcomp(svc->head_deny, yaml_document_get_node(document, map_pair->value)->data.scalar.value, REG_ICASE))
242 fatal("Service at %ld: bad HeadDeny pattern %s", vals->start_mark.line, yaml_document_get_node(document, map_pair->value)->data.scalar.value);
243 logmsg(4, "HeadDeny %s %s:%d", yaml_document_get_node(document, map_pair->value)->data.scalar.value, __FILE__, __LINE__);
244 } else if(!strcasecmp("Backends", yaml_document_get_node(document, map_pair->key)->data.scalar.value)) {
245 bes = get_svc_backends(document, yaml_document_get_node(document, map_pair->value));
246 if(utarray_len(bes) <= 0)
247 fatal("Service at %ld: no backends defined", vals->start_mark.line);
248 svc->backends_len = utarray_len(bes);
249 if((svc->backends = calloc(svc->backends_len, sizeof(BACKEND *))) == NULL)
250 fatal("Service at %ld: out of memory", vals->start_mark.line);
251 for(i = 0; i < svc->backends_len; i++)
252 svc->backends[i] = *(BACKEND **)utarray_eltptr(bes, i);
253 utarray_free(bes);
254 } else
255 fatal("Unknown directive %s at line %ld", yaml_document_get_node(document, map_pair->key)->data.scalar.value,
256 yaml_document_get_node(document, map_pair->key)->start_mark.line);
257 }
258 logmsg(2, "push %s:%d", __FILE__, __LINE__);
259 utarray_push_back(res, &svc);
260 }
261
262 return res;
263 }
264
265 static void
266 get_http(yaml_document_t *document, yaml_node_t *root)
267 {
268 yaml_node_pair_t *map_pairs;
269 yaml_node_item_t *cur;
270 yaml_node_t *vals;
271 HTTP_LISTENER res;
272 char addr[NI_MAXHOST], port[NI_MAXSERV];
273 struct addrinfo hints;
274 UT_array *services;
275 int i;
276
277 logmsg(1, "start get_http %s:%d", __FILE__, __LINE__);
278 memset(&hints, '\0', sizeof(hints));
279 hints.ai_family = AF_UNSPEC;
280 hints.ai_socktype = SOCK_STREAM;
281 memset(&res, '\0', sizeof(res));
282 for(cur = root->data.sequence.items.start; cur < root->data.sequence.items.top; cur++) {
283 vals = yaml_document_get_node(document, *cur);
284 if(vals->type != YAML_MAPPING_NODE)
285 fatal("HTTPListener at %ld: not a mapping", vals->start_mark.line);
286 addr[0] ='\0';
287 port[0] = '\0';
288 for(map_pairs = vals->data.mapping.pairs.start; map_pairs < vals->data.mapping.pairs.top; map_pairs++)
289 if(!strcasecmp("Address", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
290 strncpy(addr, yaml_document_get_node(document, map_pairs->value)->data.scalar.value, NI_MAXHOST);
291 logmsg(4, "addr %s %s:%d", addr, __FILE__, __LINE__);
292 } else if(!strcasecmp("Port", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
293 strncpy(port, yaml_document_get_node(document, map_pairs->value)->data.scalar.value, NI_MAXSERV);
294 logmsg(4, "port %s %s:%d", port, __FILE__, __LINE__);
295 } else if(!strcasecmp("Client", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
296 res.client = atoi(yaml_document_get_node(document, map_pairs->value)->data.scalar.value);
297 logmsg(4, "client %d %s:%d", res.client, __FILE__, __LINE__);
298 } else if(!strcasecmp("Threads", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
299 res.threads = atoi(yaml_document_get_node(document, map_pairs->value)->data.scalar.value);
300 logmsg(4, "threads %d %s:%d", res.threads, __FILE__, __LINE__);
301 } else if(!strcasecmp("Services", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
302 services = get_services(document, yaml_document_get_node(document, map_pairs->value));
303 } else
304 fatal("Unknown directive %s at line %ld", yaml_document_get_node(document, map_pairs->key)->data.scalar.value,
305 yaml_document_get_node(document, map_pairs->key)->start_mark.line);
306 if(res.threads <= 0)
307 res.threads = 8;
308 if(res.client <= 0)
309 res.client = 5;
310 if(getaddrinfo(addr, port, &hints, &res.addr))
311 fatal("HTTPListener at %ld: unknown server %s:%s", vals->start_mark.line, addr, port);
312 if(utarray_len(services) == 0)
313 fatal("HTTPListener at %ld: no services defined", vals->start_mark.line);
314 res.services_len = utarray_len(services);
315 if((res.services = calloc(res.services_len, sizeof(SERVICE *))) == NULL)
316 fatal("HTTPListener at %ld: out of memory", vals->start_mark.line);
317 for(i = 0; i < res.services_len; i++)
318 res.services[i] = *(SERVICE **)utarray_eltptr(services, i);
319 utarray_free(services);
320 logmsg(2, "push %s:%d", __FILE__, __LINE__);
321 utarray_push_back(ut_http, &res);
322 }
323 return;
324 }
325
326 static int *
327 get_ciphers(yaml_document_t *document, yaml_node_t *root)
328 {
329 yaml_node_item_t *cur;
330 yaml_node_t *vals;
331 UT_array *list;
332 int *res, c;
333
334 logmsg(1, "start get_ciphers %s:%d", __FILE__, __LINE__);
335 utarray_new(list, &ut_int_icd);
336 if(root->type == YAML_SCALAR_NODE) {
337 logmsg(4, "cipher %s %s:%d", root->data.scalar.value, __FILE__, __LINE__);
338 if((c = mbedtls_ssl_get_ciphersuite_id(root->data.scalar.value)) <= 0)
339 fatal("Unknown cipher %s", root->data.scalar.value);
340 utarray_push_back(list, &c);
341 } else if(root->type == YAML_SEQUENCE_NODE) {
342 for(cur = root->data.sequence.items.start; cur < root->data.sequence.items.top; cur++) {
343 vals = yaml_document_get_node(document, *cur);
344 if(vals->type != YAML_SCALAR_NODE)
345 fatal("Ciphers at %ld: not a sequence", vals->start_mark.line);
346 logmsg(4, "cipher %s %s:%d", vals->data.scalar.value, __FILE__, __LINE__);
347 if((c = mbedtls_ssl_get_ciphersuite_id(vals->data.scalar.value)) <= 0)
348 fatal("Unknown cipher %s", vals->data.scalar.value);
349 utarray_push_back(list, &c);
350 }
351 } else
352 fatal("Syntax error at line %ld", root->start_mark.line);
353 if((res = calloc(utarray_len(list) + 1, sizeof(int))) == NULL)
354 fatal("Ciphers at %ld: out of memory", root->start_mark.line);
355 for(c = 0; c < utarray_len(list); c++)
356 res[c] = *((int *)utarray_eltptr(list, c));
357 res[utarray_len(list)] = 0;
358 utarray_free(list);
359 return res;
360 }
361
362 static SNI *
363 get_one(char *filename)
364 {
365 SNI *res;
366 mbedtls_x509_crt *cur;
367 mbedtls_x509_name *nd;
368 mbedtls_asn1_buf data;
369 mbedtls_x509_sequence *san;
370 regex_t *one_host;
371 UT_array *hosts;
372 UT_icd regex_icd = {sizeof(regex_t), NULL, NULL, NULL};
373 char buf[NI_MAXHOST];
374 int i, j;
375
376 logmsg(1, "start get_one(%s) %s:%d", filename, __FILE__, __LINE__);
377 if((res = malloc(sizeof(SNI))) == NULL)
378 fatal("SNI: out of memory");
379 mbedtls_x509_crt_init(&res->certificate);
380 if(mbedtls_x509_crt_parse_file(&res->certificate, filename))
381 fatal("SNI: can't read certificate %s", filename);
382 mbedtls_pk_init(&res->key);
383 if(mbedtls_pk_parse_keyfile(&res->key, filename, NULL))
384 fatal("SNI: can't read key %s", filename);
385 utarray_new(hosts, ®ex_icd);
386 for(cur = &res->certificate; cur != NULL; cur = cur->next) {
387 if(mbedtls_pk_check_pair(&cur->pk, &res->key))
388 continue;
389 for(nd = &cur->subject; nd != NULL; nd = nd->next)
390 if(MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &nd->oid) == 0) {
391 data = nd->val;
392 memset(buf, '\0', NI_MAXHOST);
393 for(i = j = 0; i < data.len; i++)
394 if(data.p[i] == '*') {
395 buf[j++] = '[';
396 buf[j++] = '^';
397 buf[j++] = '.';
398 buf[j++] = ']';
399 buf[j++] = '+';
400 } else if(data.p[i] == '.') {
401 buf[j++] = '\\';
402 buf[j++] = '.';
403 } else
404 buf[j++] = data.p[i];
405 buf[j] = '\0';
406 logmsg(4, "get_one add pattern %s %s:%d", buf, __FILE__, __LINE__);
407 if((one_host = (regex_t *)malloc(sizeof(regex_t))) == NULL)
408 fatal("Can't alloc regex for %s",buf);
409 if(regcomp(one_host, buf, REG_ICASE | REG_EXTENDED))
410 fatal("Certificate in %s: bad host name pattern %s",filename, buf);
411 utarray_push_back(hosts, one_host);
412 }
413
414 for(san = &cur->subject_alt_names; san != NULL; san = san->next)
415 if(san->buf.tag == 130) {
416 /* 130 seems to be the OID for DNS entries */
417 data = san->buf;
418 memset(buf, '\0', NI_MAXHOST);
419 for(i = j = 0; i < data.len; i++)
420 if(data.p[i] == '*') {
421 buf[j++] = '[';
422 buf[j++] = '^';
423 buf[j++] = '.';
424 buf[j++] = ']';
425 buf[j++] = '+';
426 } else if(data.p[i] == '.') {
427 buf[j++] = '\\';
428 buf[j++] = '.';
429 } else
430 buf[j++] = data.p[i];
431 buf[j] = '\0';
432 logmsg(4, "get_one add pattern %s %s:%d", buf, __FILE__, __LINE__);
433 if((one_host = (regex_t *)malloc(sizeof(regex_t))) == NULL)
434 fatal("Can't alloc regex for %s",buf);
435 if(regcomp(one_host, buf, REG_ICASE | REG_EXTENDED))
436 fatal("Certificate in %s: bad host name pattern %s",filename, buf);
437 utarray_push_back(hosts, one_host);
438 }
439 if((res->host = calloc(utarray_len(hosts), sizeof(regex_t))) == NULL)
440 fatal("SNI: out of memory");
441 res->host_len = utarray_len(hosts);
442 for(i = 0; i < res->host_len; i++)
443 res->host[i] = *((regex_t *)utarray_eltptr(hosts, i));
444 utarray_free(hosts);
445 }
446 logmsg(4, "get_one: added %d patterns %s:%d", res->host_len, __FILE__, __LINE__);
447 return res;
448 }
449
450 static SNI **
451 get_certificates(yaml_document_t *document, yaml_node_t *root)
452 {
453 yaml_node_item_t *cur;
454 yaml_node_t *vals;
455 UT_array *list;
456 UT_icd ut_sni_icd = {sizeof(SNI *), NULL, NULL, NULL};
457 SNI **res;
458 int i;
459 SNI *sni;
460
461 logmsg(1, "start get_certificates %s:%d", __FILE__, __LINE__);
462 utarray_new(list, &ut_sni_icd);
463 if(root->type == YAML_SCALAR_NODE) {
464 sni = get_one(root->data.scalar.value);
465 utarray_push_back(list, &sni);
466 } else if(root->type == YAML_SEQUENCE_NODE) {
467 for(cur = root->data.sequence.items.start; cur < root->data.sequence.items.top; cur++) {
468 vals = yaml_document_get_node(document, *cur);
469 if(vals->type != YAML_SCALAR_NODE)
470 fatal("Certificates at %ld: not a file name", vals->start_mark.line);
471 sni = get_one(vals->data.scalar.value);
472 utarray_push_back(list, &sni);
473 }
474 } else
475 fatal("Syntax error at line %ld", root->start_mark.line);
476 if((res = calloc(utarray_len(list) + 1, sizeof(SNI *))) == NULL)
477 fatal("SNI at %ld: out of memory", root->start_mark.line);
478 for(i = 0; i < utarray_len(list); i++)
479 res[i] = *(SNI **)utarray_eltptr(list, i);
480 res[utarray_len(list)] = NULL;
481 utarray_free(list);
482 return res;
483 }
484
485 const static char *alpn_protocols[] = { "h2", "http/1.1", NULL};
486
487 static void
488 get_https(yaml_document_t *document, yaml_node_t *root)
489 {
490 yaml_node_pair_t *map_pairs;
491 yaml_node_item_t *cur;
492 yaml_node_t *vals;
493 HTTP_LISTENER res;
494 char addr[NI_MAXHOST], port[NI_MAXSERV];
495 struct addrinfo hints;
496 UT_array *services;
497 int i, *ciphers;
498
499 logmsg(1, "start get_https %s:%d", __FILE__, __LINE__);
500 memset(&hints, '\0', sizeof(hints));
501 hints.ai_family = AF_UNSPEC;
502 hints.ai_socktype = SOCK_STREAM;
503 memset(&res, '\0', sizeof(res));
504 if((res.conf = malloc(sizeof(mbedtls_ssl_config))) == NULL)
505 fatal("HTTPSListener: out of memory");
506 mbedtls_ssl_config_init(res.conf);
507 mbedtls_ssl_conf_rng(res.conf, mbedtls_ctr_drbg_random, &tls_ctr_drbg);
508 mbedtls_ssl_config_defaults(res.conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
509 mbedtls_ssl_conf_alpn_protocols(res.conf, alpn_protocols);
510 mbedtls_ssl_conf_authmode(res.conf, MBEDTLS_SSL_VERIFY_NONE);
511 for(cur = root->data.sequence.items.start; cur < root->data.sequence.items.top; cur++) {
512 vals = yaml_document_get_node(document, *cur);
513 if(vals->type != YAML_MAPPING_NODE)
514 fatal("HTTPSListener at %ld: not a mapping", vals->start_mark.line);
515 addr[0] = '\0';
516 port[0] = '\0';
517 for(map_pairs = vals->data.mapping.pairs.start; map_pairs < vals->data.mapping.pairs.top; map_pairs++)
518 if(!strcasecmp("Address", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
519 strncpy(addr, yaml_document_get_node(document, map_pairs->value)->data.scalar.value, NI_MAXHOST);
520 logmsg(4, "address %s %s:%d", addr, __FILE__, __LINE__);
521 } else if(!strcasecmp("Port", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
522 strncpy(port, yaml_document_get_node(document, map_pairs->value)->data.scalar.value, NI_MAXSERV);
523 logmsg(4, "port %s %s:%d", port, __FILE__, __LINE__);
524 } else if(!strcasecmp("Client", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
525 res.client = atoi(yaml_document_get_node(document, map_pairs->value)->data.scalar.value);
526 logmsg(4, "client %d %s:%d", res.client, __FILE__, __LINE__);
527 } else if(!strcasecmp("Threads", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
528 res.threads = atoi(yaml_document_get_node(document, map_pairs->value)->data.scalar.value);
529 logmsg(4, "threads %d %s:%d", res.threads, __FILE__, __LINE__);
530 } else if(!strcasecmp("Services", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
531 services = get_services(document, yaml_document_get_node(document, map_pairs->value));
532 } else if(!strcasecmp("Certificates", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
533 res.sni = get_certificates(document, yaml_document_get_node(document, map_pairs->value));
534 } else if(!strcasecmp("Ciphers", yaml_document_get_node(document, map_pairs->key)->data.scalar.value)) {
535 ciphers = get_ciphers(document, yaml_document_get_node(document, map_pairs->value));
536 } else
537 fatal("Unknown directive %s at line %ld", yaml_document_get_node(document, map_pairs->key)->data.scalar.value,
538 yaml_document_get_node(document, map_pairs->key)->start_mark.line);
539 if(res.threads <= 0)
540 res.threads = 8;
541 if(res.client <= 0)
542 res.client = 5;
543 if(getaddrinfo(addr, port, &hints, &res.addr))
544 fatal("HTTPSListener at %ld: unknown server %s:%s", vals->start_mark.line, addr, port);
545 if(utarray_len(services) == 0)
546 fatal("HTTPSListener at %ld: no services defined", vals->start_mark.line);
547 res.services_len = utarray_len(services);
548 if((res.services = calloc(res.services_len, sizeof(SERVICE *))) == NULL)
549 fatal("HTTPSListener at %ld: out of memory", vals->start_mark.line);
550 for(i = 0; i < res.services_len; i++)
551 res.services[i] = *(SERVICE **)utarray_eltptr(services, i);
552 utarray_free(services);
553 if(ciphers != NULL)
554 mbedtls_ssl_conf_ciphersuites(res.conf, ciphers);
555 if(res.sni == NULL)
556 fatal("HTTPSListener at %ld: no certificates defined", vals->start_mark.line);
557 mbedtls_ssl_conf_sni(res.conf, do_sni, res.sni);
558 mbedtls_ssl_conf_own_cert(res.conf, &res.sni[0]->certificate, &res.sni[0]->key);
559 if(res.sni[0]->certificate.next != NULL)
560 mbedtls_ssl_conf_ca_chain(res.conf, res.sni[0]->certificate.next, NULL );
561 mbedtls_ssl_conf_read_timeout(res.conf, (uint32_t)res.client * 1000);
562 logmsg(2, "push %s:%d", __FILE__, __LINE__);
563 utarray_push_back(ut_http, &res);
564 }
565 return;
566 }
567
568 static void
569 get_others(yaml_document_t *document, yaml_node_t *root)
570 {
571 yaml_node_pair_t *cur_pair;
572 yaml_node_t *node;
573
574 logmsg(1, "start get_others %s:%d", __FILE__, __LINE__);
575 if(root->type != YAML_MAPPING_NODE)
576 fatal("YAML root not mapping (%ld)", root->start_mark.line);
577
578 for(cur_pair = root->data.mapping.pairs.start; cur_pair < root->data.mapping.pairs.top; cur_pair++) {
579 node = yaml_document_get_node(document, cur_pair->key);
580 if(node->type != YAML_SCALAR_NODE)
581 fatal("YAML key not scalar (%ld)", node->start_mark.line);
582 if(strcasecmp("Global", node->data.scalar.value)
583 && strcasecmp("Backends", node->data.scalar.value)
584 && strcasecmp("HTTPListeners", node->data.scalar.value)
585 && strcasecmp("HTTPSListeners", node->data.scalar.value))
586 fatal("YAML unknown directive %s (%ld)", node->data.scalar.value, node->start_mark.line);
587 }
588
589 return;
590 }
591
592 static yaml_node_t *
593 get_base(yaml_document_t *document, yaml_node_t *root, char *key, int type)
594 {
595 yaml_node_pair_t *cur_pair;
596 yaml_node_t *node;
597
598 for(cur_pair = root->data.mapping.pairs.start; cur_pair < root->data.mapping.pairs.top; cur_pair++) {
599 node = yaml_document_get_node(document, cur_pair->key);
600 if(!strcasecmp(key, node->data.scalar.value)) {
601 node = yaml_document_get_node(document, cur_pair->value);
602 if(node->type != type)
603 return NULL;
604 return node;
605 }
606 }
607 return NULL;
608 }
609 void
610 config(const int argc, char **argv)
611 {
612 int c_opt, o_check = 0, o_version = 0, is_key, i;
613 char *f_conf = F_CONF;
614 FILE *f_in;
615 yaml_parser_t parser;
616 yaml_document_t document;
617 yaml_node_t *root, *sub;
618 UT_icd backend_icd = {sizeof(BACKEND), NULL, NULL, NULL };
619 BACKEND *be;
620 UT_icd http_icd = {sizeof(HTTP_LISTENER), NULL, NULL, NULL };
621 HTTP_LISTENER *http;
622
623 memset(&global, '\0', sizeof(global));
624 opterr = 0;
625 global.pid = "/var/run/pound.pid";
626 global.log_level = 0;
627 while((c_opt = getopt(argc, argv, "f:cvd:p:")) > 0)
628 switch(c_opt) {
629 case 'f':
630 /* configuration file specified on the commend line */
631 f_conf = optarg;
632 logmsg(4, "config file option %s %s:%d", f_conf, __FILE__, __LINE__);
633 break;
634 case 'p':
635 /* configuration file specified on the commend line */
636 global.pid = optarg;
637 logmsg(4, "pid file option %s %s:%d", global.pid, __FILE__, __LINE__);
638 break;
639 case 'd':
640 /* debug mode: run in foreground, messages to stdout */
641 global.log_level = atoi(optarg);
642 logmsg(4, "debug option %d %s:%d", global.log_level, __FILE__, __LINE__);
643 break;
644 case 'c':
645 /* check only: parse configuration and exit */
646 o_check = 1;
647 break;
648 case 'v':
649 /* print version and exit */
650 o_version = 1;
651 break;
652 default:
653 global.log_level = 1;
654 logmsg(0, "Unknown flag %c", c_opt);
655 exit(1);
656 }
657 if(o_version) {
658 global.log_level = 1;
659 logmsg(0, "Pound version %s", VERSION);
660 exit(0);
661 }
662
663 if((f_in = fopen(f_conf, "r")) == NULL)
664 fatal("File %s not found", f_conf);
665 if(!yaml_parser_initialize(&parser))
666 fatal("Cannot initialise parser");
667 yaml_parser_set_input_file(&parser, f_in);
668
669 if(!yaml_parser_load(&parser, &document))
670 fatal("Can't load configuration - YAML error \"%s\" at line %ld", parser.problem, parser.problem_mark.line);
671 yaml_parser_delete(&parser);
672 fclose(f_in);
673
674 if((root = yaml_document_get_root_node(&document)) == NULL)
675 fatal("YAML can't get root");
676
677 utarray_new(ut_backends, &backend_icd);
678 utarray_new(ut_http, &http_icd);
679
680 get_others(&document, root);
681 if((sub = get_base(&document, root, "Global", YAML_MAPPING_NODE)) != NULL)
682 get_global(&document, sub);
683 if((sub = get_base(&document, root, "Backends", YAML_SEQUENCE_NODE)) == NULL)
684 fatal("Missing Backends section");
685 get_backends(&document, sub);
686
687 backends_len = utarray_len(ut_backends);
688 if(backends_len == 0)
689 fatal("No backends defined");
690 if((backends = calloc(backends_len, sizeof(BACKEND))) == NULL)
691 fatal("Backends: out of memory");
692 for(i = 0, be = utarray_front(ut_backends); be != NULL; i++, be = utarray_next(ut_backends, be))
693 memcpy(&backends[i], be, sizeof(BACKEND));
694 utarray_free(ut_backends);
695
696 if(get_base(&document, root, "HTTPListeners", YAML_SCALAR_NODE) == NULL) {
697 if((sub = get_base(&document, root, "HTTPListeners", YAML_SEQUENCE_NODE)) == NULL)
698 fatal("Missing HTTPListeners section");
699 get_http(&document, sub);
700 }
701 if(get_base(&document, root, "HTTPSListeners", YAML_SCALAR_NODE) == NULL) {
702 if((sub = get_base(&document, root, "HTTPSListeners", YAML_SEQUENCE_NODE)) == NULL)
703 fatal("Missing HTTPSListeners section");
704 get_https(&document, sub);
705 }
706
707 http_len = utarray_len(ut_http);
708 if(http_len > 0) {
709 if((http_listeners = calloc(http_len, sizeof(HTTP_LISTENER))) == NULL)
710 fatal("Listeners: out of memory");
711 for(i = 0, http = utarray_front(ut_http); http != NULL; i++, http = utarray_next(ut_http, http))
712 memcpy(&http_listeners[i], http, sizeof(HTTP_LISTENER));
713 }
714 utarray_free(ut_http);
715
716 if(http_len == 0)
717 fatal("No listeners defined");
718
719 yaml_document_delete(&document);
720 if(o_check)
721 exit(0);
722 return;
723 }