]>
Commit | Line | Data |
---|---|---|
d98f6a46 SS |
1 | /********************************************************** |
2 | SixXS - Automatic IPv6 Connectivity Configuration Utility | |
3 | *********************************************************** | |
4 | Copyright 2003-2005 SixXS - http://www.sixxs.net | |
5 | *********************************************************** | |
6 | common/common.c - Common Functions | |
7 | *********************************************************** | |
8 | $Author: jeroen $ | |
9 | $Id: common.c,v 1.14 2006-12-21 14:08:50 jeroen Exp $ | |
10 | $Date: 2006-12-21 14:08:50 $ | |
11 | **********************************************************/ | |
12 | ||
13 | /* Dirty dependency for Windows:GUI version */ | |
14 | #ifdef _WIN32 | |
15 | #ifndef AICCU_CONSOLE | |
16 | #include "../windows-gui/stdafx.h" | |
17 | #include "../windows-gui/AICCUApp.h" | |
18 | extern CAICCUApp theApp; | |
19 | #endif | |
20 | #endif | |
21 | ||
22 | #include "aiccu.h" | |
23 | #include "common.h" | |
24 | ||
25 | /* getline debugging? */ | |
26 | /* | |
27 | #define E(x) x | |
28 | */ | |
29 | #define E(x) {} | |
30 | ||
31 | void dologA(int level, const char *fmt, va_list ap) | |
32 | { | |
33 | #ifdef _WIN32 | |
34 | char buf[1024]; | |
35 | #endif | |
36 | /* Don't show noise */ | |
37 | if (g_aiccu && !g_aiccu->verbose && level == LOG_DEBUG) return; | |
38 | ||
39 | #ifndef _WIN32 | |
40 | if (g_aiccu && g_aiccu->daemonize > 0) vsyslog(LOG_LOCAL7|level, fmt, ap); | |
41 | else | |
42 | { | |
43 | vfprintf(stderr, fmt, ap); | |
44 | fflush(stderr); | |
45 | } | |
46 | #else | |
47 | vsnprintf(buf, sizeof(buf), fmt, ap); | |
48 | ||
49 | #ifndef AICCU_CONSOLE | |
50 | /* Use the debug facility */ | |
51 | OutputDebugString(buf); | |
52 | ||
53 | /* Store it in a log file if we are running in verbose mode */ | |
54 | if (g_aiccu && g_aiccu->verbose) | |
55 | { | |
56 | char logfile[1024]; | |
57 | FILE *f; | |
58 | ||
59 | /* Figure out the "C:\Windows" location */ | |
60 | /* as that is where we store our configuration */ | |
61 | GetWindowsDirectory(logfile, sizeof(logfile)); | |
62 | strncat(logfile, "\\aiccu.log", sizeof(logfile)); | |
63 | f = fopen(logfile, "w+"); | |
64 | if (f) | |
65 | { | |
66 | fwrite(buf, strlen(buf), 1, f); | |
67 | fclose(f); | |
68 | } | |
69 | } | |
70 | ||
71 | /* | |
72 | * Always store the last message | |
73 | * which can be displayed as errors etc. | |
74 | */ | |
75 | ||
76 | /* strip the \n */ | |
77 | if (strlen(buf) > 0) buf[strlen(buf)-1] = '\0'; | |
78 | theApp.m_sMessage = buf; | |
79 | #else | |
80 | OutputDebugString("dolog() - "); | |
81 | OutputDebugString(buf); | |
82 | fprintf(stderr, "%s", buf); | |
83 | #endif /* AICCU_CONSOLE */ | |
84 | #endif /* !_WIN32 */ | |
85 | } | |
86 | ||
87 | void dolog(int level, const char *fmt, ...) | |
88 | { | |
89 | va_list ap; | |
90 | va_start(ap, fmt); | |
91 | dologA(level, fmt, ap); | |
92 | va_end(ap); | |
93 | } | |
94 | ||
95 | /* | |
96 | * Check if an address is RFC1918 based | |
97 | * This allows us to warn the user that they are behind a NAT | |
98 | */ | |
99 | bool is_rfc1918(char *ipv4) | |
100 | { | |
101 | unsigned int addr = inet_addr(ipv4); | |
102 | bool ret = false; | |
103 | ||
104 | ||
105 | ||
106 | ret = ( /* 10.0.0.0/8 */ | |
107 | ((addr & htonl(0xff000000)) == htonl(0x0a000000)) || | |
108 | /* 172.16.0.0/12 */ | |
109 | ((addr & htonl(0xfff00000)) == htonl(0xac100000)) || | |
110 | /* 192.168.0.0/16 */ | |
111 | ((addr & htonl(0xffff0000)) == htonl(0xc0a80000))) ? true : false; | |
112 | ||
113 | dolog(LOG_DEBUG, "is_rfc1918(%s) = %s\n", ipv4, ret ? "yes" : "false"); | |
114 | ||
115 | return ret; | |
116 | } | |
117 | ||
118 | void sock_printf(TLSSOCKET sock, const char *fmt, ...) | |
119 | { | |
120 | char buf[2048]; | |
121 | unsigned int len = 0, done = 0; | |
122 | int ret; | |
123 | ||
124 | va_list ap; | |
125 | va_start(ap, fmt); | |
126 | /* When not a socket send it to the logs */ | |
127 | if (sock == NULL || sock->socket == -1) dologA(LOG_INFO, fmt, ap); | |
128 | else | |
129 | { | |
130 | /* Format the string */ | |
131 | len = vsnprintf(buf, sizeof(buf), fmt, ap); | |
132 | ||
133 | /* Send the line(s) over the network */ | |
134 | ||
135 | while (done < len) | |
136 | { | |
137 | #ifdef AICCU_GNUTLS | |
138 | if (sock->tls_active) ret = gnutls_record_send(sock->session, &buf[done], len-done); | |
139 | else | |
140 | #endif | |
141 | ret = send(sock->socket, &buf[done], len-done, 0); | |
142 | ||
143 | if (ret > 0) done+=ret; | |
144 | else break; | |
145 | } | |
146 | ||
147 | /* Show this as debug output */ | |
148 | if (g_aiccu->verbose) | |
149 | { | |
150 | /* Strip the last \n */ | |
151 | len = (int)strlen(buf); | |
152 | if (len > 0) buf[len-1] = '\0'; | |
153 | /* dump the information */ | |
154 | dolog(LOG_DEBUG, "sock_printf() : \"%s\"\n", buf); | |
155 | } | |
156 | } | |
157 | va_end(ap); | |
158 | } | |
159 | ||
160 | extern char tic_buf[2048]; | |
161 | ||
162 | /* | |
163 | * Read a line from a socket and store it in ubuf | |
164 | * Note: uses internal caching, this should be the only function | |
165 | * used to read from the sock! The internal cache is rbuf. | |
166 | */ | |
167 | int sock_getline(TLSSOCKET sock, char *rbuf, unsigned int rbuflen, unsigned int *filled, char *ubuf, unsigned int ubuflen) | |
168 | { | |
169 | unsigned int i; | |
170 | ||
171 | if (!sock) return -1; | |
172 | ||
173 | /* A closed socket? -> clear the buffer */ | |
174 | if (sock->socket == -1) | |
175 | { | |
176 | memset(rbuf, 0, rbuflen); | |
177 | *filled = 0; | |
178 | return -1; | |
179 | } | |
180 | ||
181 | /* Clear the caller supplied buffer, just in case */ | |
182 | memset(ubuf, 0, ubuflen); | |
183 | ||
184 | for (;;) | |
185 | { | |
186 | E(dolog(LOG_DEBUG, "gl() - Filled %d\n", *filled);) | |
187 | ||
188 | /* Did we still have something in the buffer? */ | |
189 | if (*filled > 0) | |
190 | { | |
191 | E(dolog(LOG_DEBUG, "gl() - Seeking newline\n");) | |
192 | ||
193 | /* Walk to the end or until we reach a \n */ | |
194 | for (i=0; (i < (*filled-1)) && (rbuf[i] != '\n'); i++); | |
195 | ||
196 | E(dolog(LOG_DEBUG, "gl() - Seeking newline - end\n");) | |
197 | ||
198 | /* Did we find a newline? */ | |
199 | if (rbuf[i] == '\n') | |
200 | { | |
201 | E(dolog(LOG_DEBUG, "gl() - Found newline at %i\n", i+1);) | |
202 | ||
203 | /* Newline with a Linefeed in front of it ? -> remove it */ | |
204 | if (rbuf[i] == '\n' && rbuf[i-1] == '\r') | |
205 | { | |
206 | E(dolog(LOG_DEBUG, "gl() - Removing LF\n");) | |
207 | i--; | |
208 | } | |
209 | E(else dolog(LOG_DEBUG, "gl() - No LF\n");) | |
210 | ||
211 | /* Copy this over to the caller */ | |
212 | memcpy(ubuf, rbuf, i); | |
213 | ||
214 | E(dolog(LOG_DEBUG, "gl() - Copied %d bytes from %x to %x\n", i, rbuf, ubuf);) | |
215 | ||
216 | /* Count the \r if it is there */ | |
217 | if (rbuf[i] == '\r') i++; | |
218 | /* Count the \n */ | |
219 | i++; | |
220 | ||
221 | /* filled = what is left in the buffer */ | |
222 | *filled -= i; | |
223 | ||
224 | E(dolog(LOG_DEBUG, "gl() - %d bytes left in the buffer\n", *filled);) | |
225 | ||
226 | /* Now move the rest of the buffer to the front */ | |
227 | if (*filled > 0) memmove(rbuf, &rbuf[i], *filled); | |
228 | else *filled = 0; | |
229 | ||
230 | /* Show this as debug output */ | |
231 | if (g_aiccu->verbose) dolog(LOG_DEBUG, "sock_getline() : \"%s\"\n", ubuf); | |
232 | ||
233 | /* We got ourselves a line in 'buf' thus return to the caller */ | |
234 | return i; | |
235 | } | |
236 | } | |
237 | ||
238 | E(dolog(LOG_DEBUG, "gl() - Trying to receive (max=%d)...\n", rbuflen-*filled-10);) | |
239 | ||
240 | /* Fill the rest of the buffer */ | |
241 | #ifdef AICCU_GNUTLS | |
242 | if (sock->tls_active) i = gnutls_record_recv(sock->session, &rbuf[*filled], rbuflen-*filled-10); | |
243 | else | |
244 | #endif | |
245 | i = recv(sock->socket, &rbuf[*filled], rbuflen-*filled-10, 0); | |
246 | ||
247 | E(dolog(LOG_DEBUG, "gl() - Received %d\n", i);) | |
248 | ||
249 | /* Fail on errors */ | |
250 | if (i <= 0) return -1; | |
251 | ||
252 | /* We got more filled space! */ | |
253 | *filled+=i; | |
254 | ||
255 | /* Buffer overflow? */ | |
256 | if ( *filled >= (rbuflen-10) || | |
257 | *filled >= (ubuflen-10) ) | |
258 | { | |
259 | dolog(LOG_ERR, "Buffer almost flowed over without receiving a newline\n"); | |
260 | return -1; | |
261 | } | |
262 | ||
263 | /* And try again in this loop ;) */ | |
264 | } | |
265 | ||
266 | /* Never reached */ | |
267 | return -1; | |
268 | } | |
269 | ||
270 | TLSSOCKET sock_alloc(void); | |
271 | TLSSOCKET sock_alloc(void) | |
272 | { | |
273 | #ifdef AICCU_GNUTLS | |
d98f6a46 SS |
274 | int ret; |
275 | #endif /* AICCU_GNUTLS*/ | |
276 | ||
277 | TLSSOCKET sock; | |
278 | ||
279 | sock = (TLSSOCKET)malloc(sizeof(*sock)); | |
280 | if (!sock) return NULL; | |
281 | ||
282 | sock->socket = -1; | |
283 | ||
284 | #ifdef AICCU_GNUTLS | |
285 | /* TLS is not active yet (use sock_gotls() for that) */ | |
286 | sock->tls_active = false; | |
287 | ||
288 | /* Initialize TLS session */ | |
289 | ret = gnutls_init(&sock->session, GNUTLS_CLIENT); | |
61a319c2 | 290 | if (ret != GNUTLS_E_SUCCESS) |
d98f6a46 SS |
291 | { |
292 | dolog(LOG_ERR, "TLS Init failed: %s (%d)\n", gnutls_strerror(ret), ret); | |
293 | free(sock); | |
294 | return NULL; | |
295 | } | |
296 | ||
297 | /* Use default priorities */ | |
61a319c2 BP |
298 | ret = gnutls_priority_set_direct(sock->session, "NORMAL", NULL); |
299 | if (ret != GNUTLS_E_SUCCESS) | |
300 | { | |
301 | dolog(LOG_ERR, "TLS set default priority failed: %s (%d)\n", gnutls_strerror(ret), ret); | |
302 | gnutls_deinit(sock->session); | |
303 | free(sock); | |
304 | return NULL; | |
305 | } | |
d98f6a46 SS |
306 | |
307 | /* Configure the x509 credentials for the current session */ | |
61a319c2 BP |
308 | ret = gnutls_credentials_set(sock->session, GNUTLS_CRD_CERTIFICATE, g_aiccu->tls_cred); |
309 | if (ret != GNUTLS_E_SUCCESS) | |
310 | { | |
311 | dolog(LOG_ERR, "TLS credentials set failed: %s (%d)\n", gnutls_strerror(ret), ret); | |
312 | gnutls_deinit(sock->session); | |
313 | free(sock); | |
314 | return NULL; | |
315 | } | |
d98f6a46 SS |
316 | |
317 | #endif /* AICCU_GNUTLS*/ | |
318 | ||
319 | return sock; | |
320 | } | |
321 | ||
322 | void sock_free(TLSSOCKET sock) | |
323 | { | |
324 | if (!sock) return; | |
325 | ||
326 | #ifdef AICCU_GNUTLS | |
327 | if (sock->tls_active) | |
328 | { | |
329 | sock->tls_active = false; | |
330 | gnutls_bye(sock->session, GNUTLS_SHUT_RDWR); | |
331 | } | |
332 | #endif /* AICCU_GNUTLS*/ | |
333 | ||
334 | if (sock->socket >= 0) | |
335 | { | |
336 | /* Stop communications */ | |
337 | shutdown(sock->socket, SHUT_RDWR); | |
338 | closesocket(sock->socket); | |
339 | sock->socket = -1; | |
340 | } | |
341 | ||
342 | #ifdef AICCU_GNUTLS | |
343 | gnutls_deinit(sock->session); | |
344 | #endif /* AICCU_GNUTLS*/ | |
345 | ||
346 | free(sock); | |
347 | } | |
348 | ||
349 | /* Connect this client to a server */ | |
350 | TLSSOCKET connect_client(const char *hostname, const char *service, int family, int socktype) | |
351 | { | |
352 | TLSSOCKET sock; | |
353 | struct addrinfo hints, *res, *ressave; | |
354 | ||
355 | sock = sock_alloc(); | |
356 | if (!sock) return NULL; | |
357 | ||
358 | memset(&hints, 0, sizeof(struct addrinfo)); | |
359 | hints.ai_family = family; | |
360 | hints.ai_socktype = socktype; | |
361 | ||
362 | if (getaddrinfo(hostname, service, &hints, &res) != 0) | |
363 | { | |
364 | dolog(LOG_ERR, "Couldn't resolve host %s, service %s\n", hostname, service); | |
365 | sock_free(sock); | |
366 | return NULL; | |
367 | } | |
368 | ||
369 | ressave = res; | |
370 | ||
371 | while (res) | |
372 | { | |
373 | sock->socket = socket(res->ai_family, res->ai_socktype, res->ai_protocol); | |
374 | if (sock->socket == -1) continue; | |
375 | if (connect(sock->socket, res->ai_addr, (unsigned int)res->ai_addrlen) == 0) break; | |
376 | closesocket(sock->socket); | |
377 | sock->socket = -1; | |
378 | res = res->ai_next; | |
379 | } | |
380 | ||
381 | freeaddrinfo(ressave); | |
382 | ||
383 | if (sock->socket == -1) | |
384 | { | |
385 | sock_free(sock); | |
386 | sock = NULL; | |
387 | } | |
388 | ||
389 | return sock; | |
390 | } | |
391 | ||
392 | TLSSOCKET listen_server(const char *description, const char *hostname, const char *service, int family, int socktype) | |
393 | { | |
394 | struct addrinfo hints, *res, *ressave; | |
395 | int n; | |
396 | TLSSOCKET sock; | |
397 | socklen_t on = 1; | |
398 | /* | |
399 | D(dolog(LOG_DEBUG, "[%s] Trying to get socket for [%s]:%s over %s (%d) using %s (%d)\n", | |
400 | description, hostname, service, | |
401 | family == AF_INET ? "IPv4" : (family == AF_INET6 ? "IPv6" : "??"), | |
402 | family, | |
403 | socktype == IPPROTO_UDP ? "UDP" : (socktype == IPPROTO_TCP ? "TCP" : "??"), | |
404 | socktype);) | |
405 | */ | |
406 | sock = sock_alloc(); | |
407 | if (!sock) return NULL; | |
408 | ||
409 | memset(&hints, 0, sizeof(struct addrinfo)); | |
410 | ||
411 | /* AI_PASSIVE flag: the resulting address is used to bind | |
412 | to a socket for accepting incoming connections. | |
413 | So, when the hostname==NULL, getaddrinfo function will | |
414 | return one entry per allowed protocol family containing | |
415 | the unspecified address for that family. */ | |
416 | ||
417 | hints.ai_flags = AI_PASSIVE; | |
418 | hints.ai_family = family; | |
419 | hints.ai_socktype = socktype; | |
420 | ||
421 | n = getaddrinfo(hostname, service, &hints, &res); | |
422 | if (n < 0) | |
423 | { | |
424 | dolog(LOG_ERR, "[%s] listen_server setup: getaddrinfo error: %s\n", description, gai_strerror(n)); | |
425 | sock_free(sock); | |
426 | return NULL; | |
427 | } | |
428 | ||
429 | ressave=res; | |
430 | ||
431 | /* Try to open socket with each address getaddrinfo returned, | |
432 | until we get one valid listening socket. */ | |
433 | while (res) | |
434 | { | |
435 | sock->socket = socket(res->ai_family, res->ai_socktype, res->ai_protocol); | |
436 | if (!(sock->socket < 0)) | |
437 | { | |
438 | setsockopt(sock->socket, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)); | |
439 | if (bind(sock->socket, res->ai_addr, (unsigned int)res->ai_addrlen) == 0) break; | |
440 | closesocket(sock->socket); | |
441 | sock->socket = -1; | |
442 | } | |
443 | res = res->ai_next; | |
444 | } | |
445 | ||
446 | freeaddrinfo(ressave); | |
447 | ||
448 | if (sock->socket < 0) | |
449 | { | |
450 | dolog(LOG_ERR, "[%s] listen setup: socket error: could not open socket\n", description); | |
451 | sock_free(sock); | |
452 | return NULL; | |
453 | } | |
454 | ||
455 | if (listen(sock->socket, LISTEN_QUEUE) == -1) | |
456 | { | |
457 | dolog(LOG_ERR, "[%s] listen setup: socket error: could not listen on socket\n", description); | |
458 | sock_free(sock); | |
459 | return NULL; | |
460 | } | |
461 | ||
462 | dolog(LOG_INFO, "[%s] Listening on [%s]:%s\n", description, hostname, service); | |
463 | ||
464 | return sock; | |
465 | } | |
466 | ||
467 | /* | |
468 | * Put a socket into TLS mode | |
469 | */ | |
470 | #ifdef AICCU_GNUTLS | |
471 | bool sock_gotls(TLSSOCKET sock) | |
472 | { | |
473 | int ret = 0; | |
474 | ||
475 | if (!sock) return false; | |
476 | ||
477 | if (sock->tls_active) | |
478 | { | |
479 | dolog(LOG_ERR, "Can't go into TLS mode twice!?\n"); | |
480 | return false; | |
481 | } | |
482 | ||
483 | /* Set the transport */ | |
484 | gnutls_transport_set_ptr(sock->session, (gnutls_transport_ptr)sock->socket); | |
485 | ||
486 | /* Perform the TLS handshake */ | |
487 | ret = gnutls_handshake(sock->session); | |
488 | if (ret < 0) | |
489 | { | |
490 | dolog(LOG_ERR, "TLS Handshake failed: %s (%d)\n", gnutls_strerror(ret), ret); | |
491 | return false; | |
492 | } | |
493 | ||
ddeba48a | 494 | dolog(LOG_DEBUG, "TLS Handshake completed successfully\n"); |
d98f6a46 SS |
495 | |
496 | sock->tls_active = true; | |
497 | return true; | |
498 | } | |
499 | #endif | |
500 | ||
501 | /* Count the number of fields in <s> */ | |
502 | unsigned int countfields(char *s) | |
503 | { | |
504 | int n = 1, i; | |
505 | if (s == NULL) return 0; | |
506 | for (i=0; s[i] != '\0'; i++) if (s[i] == ' ') n++; | |
507 | return n; | |
508 | } | |
509 | ||
510 | /* | |
511 | * Copy field <n> of string <s> into <buf> with a maximum of buflen | |
512 | * First field is 1 | |
513 | */ | |
514 | bool copyfield(char *s, unsigned int n, char *buf, unsigned int buflen) | |
515 | { | |
516 | unsigned int begin = 0, i=0; | |
517 | ||
518 | /* Clear the buffer */ | |
519 | memset(buf, 0, buflen); | |
520 | ||
521 | while (s[i] != '\0') | |
522 | { | |
523 | n--; | |
524 | begin = i; | |
525 | ||
526 | /* Find next delimiter */ | |
527 | for (; s[i] != '\0' && s[i] != ' '; i++); | |
528 | ||
529 | if (n == 0) | |
530 | { | |
531 | i-=begin; | |
532 | strncpy(buf, s+begin, i > buflen ? buflen : i); | |
533 | /* dolog(LOG_DEBUG, "copyfield() : '%s', begin = %d, len = %d\n", buf, begin, i); */ | |
534 | return true; | |
535 | } | |
536 | ||
537 | i++; | |
538 | } | |
539 | dolog(LOG_WARNING, "copyfield() - Field %u didn't exist in '%s'\n", n, s); | |
540 | return false; | |
541 | } | |
542 | ||
543 | bool parseline(char *line, const char *split, struct pl_rule *rules, void *data) | |
544 | { | |
545 | unsigned int r, len; | |
546 | char *end = NULL, *val = NULL, *p = NULL; | |
547 | void *store; | |
548 | ||
549 | /* Chop off \n and \r and white space */ | |
550 | p = &line[strlen(line)-1]; | |
551 | while ( p >= line && ( | |
552 | *p == '\n' || | |
553 | *p == '\r' || | |
554 | *p == '\t' || | |
555 | *p == ' ')) *p-- = '\0'; | |
556 | ||
557 | /* Ignore comments and emtpy lines */ | |
558 | if ( strlen(line) == 0 || | |
559 | line[0] == '#' || | |
560 | line[0] == ';' || | |
561 | (line[0] == '/' && line[1] == '/')) | |
562 | { | |
563 | return true; | |
564 | } | |
565 | ||
566 | /* Get the end of the first argument */ | |
567 | p = line; | |
568 | end = &line[strlen(line)-1]; | |
569 | /* Skip until whitespace */ | |
570 | while ( p < end && | |
571 | strncmp(p, split, strlen(split)) != 0) p++; | |
572 | /* Terminate this argument */ | |
573 | *p = '\0'; | |
574 | p++; | |
575 | ||
576 | /* Skip whitespace */ | |
577 | while ( p < end && | |
578 | *p == ' ' && | |
579 | *p == '\t') p++; | |
580 | ||
581 | /* Start of the value */ | |
582 | val = p+(strlen(split)-1); | |
583 | ||
584 | /* If starting with quotes, skip until next quote */ | |
585 | if (*p == '"' || *p == '\'') | |
586 | { | |
587 | p++; | |
588 | /* Find next quote */ | |
589 | while (p <= end && | |
590 | *p != *val && | |
591 | *p != '\0') p++; | |
592 | /* Terminate */ | |
593 | *p = '\0'; | |
594 | /* Skip the first quote */ | |
595 | val++; | |
596 | } | |
597 | /* Otherwise it is already terminated above */ | |
598 | ||
599 | /* Walk through all the rules */ | |
600 | for (r = 0; rules[r].type != PLRT_END; r++) | |
601 | { | |
602 | len = (int)strlen(rules[r].title); | |
603 | if (strncmp(line, rules[r].title, len) != 0) continue; | |
604 | ||
605 | store = (void *)((char *)data + rules[r].offset); | |
606 | ||
607 | switch (rules[r].type) | |
608 | { | |
609 | case PLRT_STRING: | |
610 | if (*((char **)store)) free(*((char **)store)); | |
611 | *((char **)store) = strdup(val); | |
612 | break; | |
613 | ||
614 | case PLRT_INTEGER: | |
615 | *((uint32_t *)store) = atoi(val); | |
616 | break; | |
617 | ||
618 | case PLRT_BOOL: | |
619 | if ( strcmp(val, "yes") == 0 || | |
620 | strcmp(val, "true") == 0) | |
621 | { | |
622 | *((bool *)store) = true; | |
623 | } | |
624 | else if (strcmp(val, "no") == 0 || | |
625 | strcmp(val, "false") == 0) | |
626 | { | |
627 | *((bool *)store) = false; | |
628 | } | |
629 | else | |
630 | { | |
631 | dolog(LOG_WARNING, "Unknown boolean value \"%s\" for option \"%s\"\n", val, rules[r].title); | |
632 | } | |
633 | break; | |
634 | ||
635 | case PLRT_IPV4: | |
636 | inet_pton(AF_INET, val, store); | |
637 | break; | |
638 | ||
639 | case PLRT_IPV6: | |
640 | inet_pton(AF_INET6, val, store); | |
641 | break; | |
642 | ||
643 | case PLRT_END: | |
644 | return false; | |
645 | } | |
646 | return true; | |
647 | } | |
648 | return false; | |
649 | } | |
650 | ||
651 | /* | |
652 | * MD5 a string | |
653 | * sSignature's size MUST be 32 bytes! | |
654 | */ | |
655 | void MD5String(const char *sString, char *sSignature, unsigned int siglen) | |
656 | { | |
657 | struct MD5Context md5c; | |
658 | unsigned char signature[16]; | |
659 | unsigned int i; | |
660 | ||
661 | if (siglen < 32) return; | |
662 | ||
663 | /* Initialize MD5 structure */ | |
664 | MD5Init(&md5c); | |
665 | /* Calculate MD5 of the string */ | |
666 | MD5Update(&md5c, (unsigned char *)sString, (unsigned int)strlen(sString)); | |
667 | MD5Final(signature, &md5c); | |
668 | ||
669 | memset(sSignature, 0, siglen); | |
670 | ||
671 | for (i=0; i < sizeof(signature); i++) | |
672 | { | |
673 | snprintf(&sSignature[i*2], 3, "%02x", signature[i]); | |
674 | } | |
675 | } | |
676 | ||
677 | #ifdef _AIX | |
678 | /* AIX doesn't have vsyslog() thus we implement it here */ | |
679 | void vsyslog(int priority, const char *format, va_list ap) | |
680 | { | |
681 | char buf[1024]; | |
682 | vsnprintf(buf, sizeof(buf), format, ap); | |
683 | syslog(priority, buf); | |
684 | } | |
685 | #endif | |
686 | ||
687 | #ifdef _WIN32 | |
688 | const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) | |
689 | { | |
690 | if (af == AF_INET) | |
691 | { | |
692 | struct sockaddr_in in; | |
693 | memset(&in, 0, sizeof(in)); | |
694 | in.sin_family = AF_INET; | |
695 | memcpy(&in.sin_addr, src, sizeof(struct in_addr)); | |
696 | getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST); | |
697 | return dst; | |
698 | } | |
699 | else if (af == AF_INET6) | |
700 | { | |
701 | struct sockaddr_in6 in; | |
702 | memset(&in, 0, sizeof(in)); | |
703 | in.sin6_family = AF_INET6; | |
704 | memcpy(&in.sin6_addr, src, sizeof(struct in_addr6)); | |
705 | getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST); | |
706 | return dst; | |
707 | } | |
708 | return NULL; | |
709 | } | |
710 | ||
711 | int inet_pton(int af, const char *src, void *dst) | |
712 | { | |
713 | struct addrinfo hints, *res, *ressave; | |
714 | ||
715 | memset(&hints, 0, sizeof(struct addrinfo)); | |
716 | hints.ai_family = af; | |
717 | ||
718 | if (getaddrinfo(src, NULL, &hints, &res) != 0) | |
719 | { | |
720 | dolog(LOG_ERR, "Couldn't resolve host %s\n", src); | |
721 | return -1; | |
722 | } | |
723 | ||
724 | ressave = res; | |
725 | ||
726 | while (res) | |
727 | { | |
728 | /* Check if AF is correct */ | |
729 | if (res->ai_family != af) | |
730 | { | |
731 | res = res->ai_next; | |
732 | continue; | |
733 | } | |
734 | ||
735 | /* This is the one we want */ | |
736 | memcpy(dst, res->ai_addr, af == AF_INET6 ? sizeof(struct in_addr6) : sizeof(struct in_addr)); | |
737 | ||
738 | /* We only need one */ | |
739 | break; | |
740 | } | |
741 | ||
742 | freeaddrinfo(ressave); | |
743 | return 0; | |
744 | } | |
745 | ||
746 | #endif |