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 ***********************************************************
9 $Id: common.c,v 1.14 2006-12-21 14:08:50 jeroen Exp $
10 $Date: 2006-12-21 14:08:50 $
11 **********************************************************/
13 /* Dirty dependency for Windows:GUI version */
16 #include "../windows-gui/stdafx.h"
17 #include "../windows-gui/AICCUApp.h"
18 extern CAICCUApp theApp
;
25 /* getline debugging? */
31 void dologA(int level
, const char *fmt
, va_list ap
)
36 /* Don't show noise */
37 if (g_aiccu
&& !g_aiccu
->verbose
&& level
== LOG_DEBUG
) return;
40 if (g_aiccu
&& g_aiccu
->daemonize
> 0) vsyslog(LOG_LOCAL7
|level
, fmt
, ap
);
43 vfprintf(stderr
, fmt
, ap
);
47 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
50 /* Use the debug facility */
51 OutputDebugString(buf
);
53 /* Store it in a log file if we are running in verbose mode */
54 if (g_aiccu
&& g_aiccu
->verbose
)
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+");
66 fwrite(buf
, strlen(buf
), 1, f
);
72 * Always store the last message
73 * which can be displayed as errors etc.
77 if (strlen(buf
) > 0) buf
[strlen(buf
)-1] = '\0';
78 theApp
.m_sMessage
= buf
;
80 OutputDebugString("dolog() - ");
81 OutputDebugString(buf
);
82 fprintf(stderr
, "%s", buf
);
83 #endif /* AICCU_CONSOLE */
87 void dolog(int level
, const char *fmt
, ...)
91 dologA(level
, fmt
, ap
);
96 * Check if an address is RFC1918 based
97 * This allows us to warn the user that they are behind a NAT
99 bool is_rfc1918(char *ipv4
)
101 unsigned int addr
= inet_addr(ipv4
);
106 ret
= ( /* 10.0.0.0/8 */
107 ((addr
& htonl(0xff000000)) == htonl(0x0a000000)) ||
109 ((addr
& htonl(0xfff00000)) == htonl(0xac100000)) ||
111 ((addr
& htonl(0xffff0000)) == htonl(0xc0a80000))) ? true : false;
113 dolog(LOG_DEBUG
, "is_rfc1918(%s) = %s\n", ipv4
, ret
? "yes" : "false");
118 void sock_printf(TLSSOCKET sock
, const char *fmt
, ...)
121 unsigned int len
= 0, done
= 0;
126 /* When not a socket send it to the logs */
127 if (sock
== NULL
|| sock
->socket
== -1) dologA(LOG_INFO
, fmt
, ap
);
130 /* Format the string */
131 len
= vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
133 /* Send the line(s) over the network */
138 if (sock
->tls_active
) ret
= gnutls_record_send(sock
->session
, &buf
[done
], len
-done
);
141 ret
= send(sock
->socket
, &buf
[done
], len
-done
, 0);
143 if (ret
> 0) done
+=ret
;
147 /* Show this as debug output */
148 if (g_aiccu
->verbose
)
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
);
160 extern char tic_buf
[2048];
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.
167 int sock_getline(TLSSOCKET sock
, char *rbuf
, unsigned int rbuflen
, unsigned int *filled
, char *ubuf
, unsigned int ubuflen
)
171 if (!sock
) return -1;
173 /* A closed socket? -> clear the buffer */
174 if (sock
->socket
== -1)
176 memset(rbuf
, 0, rbuflen
);
181 /* Clear the caller supplied buffer, just in case */
182 memset(ubuf
, 0, ubuflen
);
186 E(dolog(LOG_DEBUG
, "gl() - Filled %d\n", *filled
);)
188 /* Did we still have something in the buffer? */
191 E(dolog(LOG_DEBUG
, "gl() - Seeking newline\n");)
193 /* Walk to the end or until we reach a \n */
194 for (i
=0; (i
< (*filled
-1)) && (rbuf
[i
] != '\n'); i
++);
196 E(dolog(LOG_DEBUG
, "gl() - Seeking newline - end\n");)
198 /* Did we find a newline? */
201 E(dolog(LOG_DEBUG
, "gl() - Found newline at %i\n", i
+1);)
203 /* Newline with a Linefeed in front of it ? -> remove it */
204 if (rbuf
[i
] == '\n' && rbuf
[i
-1] == '\r')
206 E(dolog(LOG_DEBUG
, "gl() - Removing LF\n");)
209 E(else dolog(LOG_DEBUG
, "gl() - No LF\n");)
211 /* Copy this over to the caller */
212 memcpy(ubuf
, rbuf
, i
);
214 E(dolog(LOG_DEBUG
, "gl() - Copied %d bytes from %x to %x\n", i
, rbuf
, ubuf
);)
216 /* Count the \r if it is there */
217 if (rbuf
[i
] == '\r') i
++;
221 /* filled = what is left in the buffer */
224 E(dolog(LOG_DEBUG
, "gl() - %d bytes left in the buffer\n", *filled
);)
226 /* Now move the rest of the buffer to the front */
227 if (*filled
> 0) memmove(rbuf
, &rbuf
[i
], *filled
);
230 /* Show this as debug output */
231 if (g_aiccu
->verbose
) dolog(LOG_DEBUG
, "sock_getline() : \"%s\"\n", ubuf
);
233 /* We got ourselves a line in 'buf' thus return to the caller */
238 E(dolog(LOG_DEBUG
, "gl() - Trying to receive (max=%d)...\n", rbuflen
-*filled
-10);)
240 /* Fill the rest of the buffer */
242 if (sock
->tls_active
) i
= gnutls_record_recv(sock
->session
, &rbuf
[*filled
], rbuflen
-*filled
-10);
245 i
= recv(sock
->socket
, &rbuf
[*filled
], rbuflen
-*filled
-10, 0);
247 E(dolog(LOG_DEBUG
, "gl() - Received %d\n", i
);)
250 if (i
<= 0) return -1;
252 /* We got more filled space! */
255 /* Buffer overflow? */
256 if ( *filled
>= (rbuflen
-10) ||
257 *filled
>= (ubuflen
-10) )
259 dolog(LOG_ERR
, "Buffer almost flowed over without receiving a newline\n");
263 /* And try again in this loop ;) */
270 TLSSOCKET
sock_alloc(void);
271 TLSSOCKET
sock_alloc(void)
274 /* Allow connections to servers that have OpenPGP keys as well */
275 const int cert_type_priority
[3] = { GNUTLS_CRT_X509
, GNUTLS_CRT_OPENPGP
, 0 };
277 #endif /* AICCU_GNUTLS*/
281 sock
= (TLSSOCKET
)malloc(sizeof(*sock
));
282 if (!sock
) return NULL
;
287 /* TLS is not active yet (use sock_gotls() for that) */
288 sock
->tls_active
= false;
290 /* Initialize TLS session */
291 ret
= gnutls_init(&sock
->session
, GNUTLS_CLIENT
);
294 dolog(LOG_ERR
, "TLS Init failed: %s (%d)\n", gnutls_strerror(ret
), ret
);
299 /* Use default priorities */
300 gnutls_set_default_priority(sock
->session
);
301 /* XXX: Return value is not documented in GNUTLS documentation! */
303 gnutls_certificate_type_set_priority(sock
->session
, cert_type_priority
);
304 /* XXX: Return value is not documented in GNUTLS documentation! */
306 /* Configure the x509 credentials for the current session */
307 gnutls_credentials_set(sock
->session
, GNUTLS_CRD_CERTIFICATE
, g_aiccu
->tls_cred
);
308 /* XXX: Return value is not documented in GNUTLS documentation! */
310 #endif /* AICCU_GNUTLS*/
315 void sock_free(TLSSOCKET sock
)
320 if (sock
->tls_active
)
322 sock
->tls_active
= false;
323 gnutls_bye(sock
->session
, GNUTLS_SHUT_RDWR
);
325 #endif /* AICCU_GNUTLS*/
327 if (sock
->socket
>= 0)
329 /* Stop communications */
330 shutdown(sock
->socket
, SHUT_RDWR
);
331 closesocket(sock
->socket
);
336 gnutls_deinit(sock
->session
);
337 #endif /* AICCU_GNUTLS*/
342 /* Connect this client to a server */
343 TLSSOCKET
connect_client(const char *hostname
, const char *service
, int family
, int socktype
)
346 struct addrinfo hints
, *res
, *ressave
;
349 if (!sock
) return NULL
;
351 memset(&hints
, 0, sizeof(struct addrinfo
));
352 hints
.ai_family
= family
;
353 hints
.ai_socktype
= socktype
;
355 if (getaddrinfo(hostname
, service
, &hints
, &res
) != 0)
357 dolog(LOG_ERR
, "Couldn't resolve host %s, service %s\n", hostname
, service
);
366 sock
->socket
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
367 if (sock
->socket
== -1) continue;
368 if (connect(sock
->socket
, res
->ai_addr
, (unsigned int)res
->ai_addrlen
) == 0) break;
369 closesocket(sock
->socket
);
374 freeaddrinfo(ressave
);
376 if (sock
->socket
== -1)
385 TLSSOCKET
listen_server(const char *description
, const char *hostname
, const char *service
, int family
, int socktype
)
387 struct addrinfo hints
, *res
, *ressave
;
392 D(dolog(LOG_DEBUG, "[%s] Trying to get socket for [%s]:%s over %s (%d) using %s (%d)\n",
393 description, hostname, service,
394 family == AF_INET ? "IPv4" : (family == AF_INET6 ? "IPv6" : "??"),
396 socktype == IPPROTO_UDP ? "UDP" : (socktype == IPPROTO_TCP ? "TCP" : "??"),
400 if (!sock
) return NULL
;
402 memset(&hints
, 0, sizeof(struct addrinfo
));
404 /* AI_PASSIVE flag: the resulting address is used to bind
405 to a socket for accepting incoming connections.
406 So, when the hostname==NULL, getaddrinfo function will
407 return one entry per allowed protocol family containing
408 the unspecified address for that family. */
410 hints
.ai_flags
= AI_PASSIVE
;
411 hints
.ai_family
= family
;
412 hints
.ai_socktype
= socktype
;
414 n
= getaddrinfo(hostname
, service
, &hints
, &res
);
417 dolog(LOG_ERR
, "[%s] listen_server setup: getaddrinfo error: %s\n", description
, gai_strerror(n
));
424 /* Try to open socket with each address getaddrinfo returned,
425 until we get one valid listening socket. */
428 sock
->socket
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
429 if (!(sock
->socket
< 0))
431 setsockopt(sock
->socket
, SOL_SOCKET
, SO_REUSEADDR
, (const char *)&on
, sizeof(on
));
432 if (bind(sock
->socket
, res
->ai_addr
, (unsigned int)res
->ai_addrlen
) == 0) break;
433 closesocket(sock
->socket
);
439 freeaddrinfo(ressave
);
441 if (sock
->socket
< 0)
443 dolog(LOG_ERR
, "[%s] listen setup: socket error: could not open socket\n", description
);
448 if (listen(sock
->socket
, LISTEN_QUEUE
) == -1)
450 dolog(LOG_ERR
, "[%s] listen setup: socket error: could not listen on socket\n", description
);
455 dolog(LOG_INFO
, "[%s] Listening on [%s]:%s\n", description
, hostname
, service
);
461 * Put a socket into TLS mode
464 bool sock_gotls(TLSSOCKET sock
)
468 if (!sock
) return false;
470 if (sock
->tls_active
)
472 dolog(LOG_ERR
, "Can't go into TLS mode twice!?\n");
476 /* Set the transport */
477 gnutls_transport_set_ptr(sock
->session
, (gnutls_transport_ptr
)sock
->socket
);
479 /* Perform the TLS handshake */
480 ret
= gnutls_handshake(sock
->session
);
483 dolog(LOG_ERR
, "TLS Handshake failed: %s (%d)\n", gnutls_strerror(ret
), ret
);
487 dolog(LOG_DEBUG
, "TLS Handshake completed succesfully\n");
489 sock
->tls_active
= true;
494 /* Count the number of fields in <s> */
495 unsigned int countfields(char *s
)
498 if (s
== NULL
) return 0;
499 for (i
=0; s
[i
] != '\0'; i
++) if (s
[i
] == ' ') n
++;
504 * Copy field <n> of string <s> into <buf> with a maximum of buflen
507 bool copyfield(char *s
, unsigned int n
, char *buf
, unsigned int buflen
)
509 unsigned int begin
= 0, i
=0;
511 /* Clear the buffer */
512 memset(buf
, 0, buflen
);
519 /* Find next delimiter */
520 for (; s
[i
] != '\0' && s
[i
] != ' '; i
++);
525 strncpy(buf
, s
+begin
, i
> buflen
? buflen
: i
);
526 /* dolog(LOG_DEBUG, "copyfield() : '%s', begin = %d, len = %d\n", buf, begin, i); */
532 dolog(LOG_WARNING
, "copyfield() - Field %u didn't exist in '%s'\n", n
, s
);
536 bool parseline(char *line
, const char *split
, struct pl_rule
*rules
, void *data
)
539 char *end
= NULL
, *val
= NULL
, *p
= NULL
;
542 /* Chop off \n and \r and white space */
543 p
= &line
[strlen(line
)-1];
544 while ( p
>= line
&& (
548 *p
== ' ')) *p
-- = '\0';
550 /* Ignore comments and emtpy lines */
551 if ( strlen(line
) == 0 ||
554 (line
[0] == '/' && line
[1] == '/'))
559 /* Get the end of the first argument */
561 end
= &line
[strlen(line
)-1];
562 /* Skip until whitespace */
564 strncmp(p
, split
, strlen(split
)) != 0) p
++;
565 /* Terminate this argument */
569 /* Skip whitespace */
574 /* Start of the value */
575 val
= p
+(strlen(split
)-1);
577 /* If starting with quotes, skip until next quote */
578 if (*p
== '"' || *p
== '\'')
581 /* Find next quote */
587 /* Skip the first quote */
590 /* Otherwise it is already terminated above */
592 /* Walk through all the rules */
593 for (r
= 0; rules
[r
].type
!= PLRT_END
; r
++)
595 len
= (int)strlen(rules
[r
].title
);
596 if (strncmp(line
, rules
[r
].title
, len
) != 0) continue;
598 store
= (void *)((char *)data
+ rules
[r
].offset
);
600 switch (rules
[r
].type
)
603 if (*((char **)store
)) free(*((char **)store
));
604 *((char **)store
) = strdup(val
);
608 *((uint32_t *)store
) = atoi(val
);
612 if ( strcmp(val
, "yes") == 0 ||
613 strcmp(val
, "true") == 0)
615 *((bool *)store
) = true;
617 else if (strcmp(val
, "no") == 0 ||
618 strcmp(val
, "false") == 0)
620 *((bool *)store
) = false;
624 dolog(LOG_WARNING
, "Unknown boolean value \"%s\" for option \"%s\"\n", val
, rules
[r
].title
);
629 inet_pton(AF_INET
, val
, store
);
633 inet_pton(AF_INET6
, val
, store
);
646 * sSignature's size MUST be 32 bytes!
648 void MD5String(const char *sString
, char *sSignature
, unsigned int siglen
)
650 struct MD5Context md5c
;
651 unsigned char signature
[16];
654 if (siglen
< 32) return;
656 /* Initialize MD5 structure */
658 /* Calculate MD5 of the string */
659 MD5Update(&md5c
, (unsigned char *)sString
, (unsigned int)strlen(sString
));
660 MD5Final(signature
, &md5c
);
662 memset(sSignature
, 0, siglen
);
664 for (i
=0; i
< sizeof(signature
); i
++)
666 snprintf(&sSignature
[i
*2], 3, "%02x", signature
[i
]);
671 /* AIX doesn't have vsyslog() thus we implement it here */
672 void vsyslog(int priority
, const char *format
, va_list ap
)
675 vsnprintf(buf
, sizeof(buf
), format
, ap
);
676 syslog(priority
, buf
);
681 const char *inet_ntop(int af
, const void *src
, char *dst
, socklen_t cnt
)
685 struct sockaddr_in in
;
686 memset(&in
, 0, sizeof(in
));
687 in
.sin_family
= AF_INET
;
688 memcpy(&in
.sin_addr
, src
, sizeof(struct in_addr
));
689 getnameinfo((struct sockaddr
*)&in
, sizeof(struct sockaddr_in
), dst
, cnt
, NULL
, 0, NI_NUMERICHOST
);
692 else if (af
== AF_INET6
)
694 struct sockaddr_in6 in
;
695 memset(&in
, 0, sizeof(in
));
696 in
.sin6_family
= AF_INET6
;
697 memcpy(&in
.sin6_addr
, src
, sizeof(struct in_addr6
));
698 getnameinfo((struct sockaddr
*)&in
, sizeof(struct sockaddr_in6
), dst
, cnt
, NULL
, 0, NI_NUMERICHOST
);
704 int inet_pton(int af
, const char *src
, void *dst
)
706 struct addrinfo hints
, *res
, *ressave
;
708 memset(&hints
, 0, sizeof(struct addrinfo
));
709 hints
.ai_family
= af
;
711 if (getaddrinfo(src
, NULL
, &hints
, &res
) != 0)
713 dolog(LOG_ERR
, "Couldn't resolve host %s\n", src
);
721 /* Check if AF is correct */
722 if (res
->ai_family
!= af
)
728 /* This is the one we want */
729 memcpy(dst
, res
->ai_addr
, af
== AF_INET6
? sizeof(struct in_addr6
) : sizeof(struct in_addr
));
731 /* We only need one */
735 freeaddrinfo(ressave
);