]>
git.ipfire.org Git - people/stevee/aiccu.git/blob - common/common.c
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)
275 #endif /* AICCU_GNUTLS*/
279 sock
= (TLSSOCKET
)malloc(sizeof(*sock
));
280 if (!sock
) return NULL
;
285 /* TLS is not active yet (use sock_gotls() for that) */
286 sock
->tls_active
= false;
288 /* Initialize TLS session */
289 ret
= gnutls_init(&sock
->session
, GNUTLS_CLIENT
);
290 if (ret
!= GNUTLS_E_SUCCESS
)
292 dolog(LOG_ERR
, "TLS Init failed: %s (%d)\n", gnutls_strerror(ret
), ret
);
297 /* Use default priorities */
298 ret
= gnutls_priority_set_direct(sock
->session
, "NORMAL", NULL
);
299 if (ret
!= GNUTLS_E_SUCCESS
)
301 dolog(LOG_ERR
, "TLS set default priority failed: %s (%d)\n", gnutls_strerror(ret
), ret
);
302 gnutls_deinit(sock
->session
);
307 /* Configure the x509 credentials for the current session */
308 ret
= gnutls_credentials_set(sock
->session
, GNUTLS_CRD_CERTIFICATE
, g_aiccu
->tls_cred
);
309 if (ret
!= GNUTLS_E_SUCCESS
)
311 dolog(LOG_ERR
, "TLS credentials set failed: %s (%d)\n", gnutls_strerror(ret
), ret
);
312 gnutls_deinit(sock
->session
);
317 #endif /* AICCU_GNUTLS*/
322 void sock_free(TLSSOCKET sock
)
327 if (sock
->tls_active
)
329 sock
->tls_active
= false;
330 gnutls_bye(sock
->session
, GNUTLS_SHUT_RDWR
);
332 #endif /* AICCU_GNUTLS*/
334 if (sock
->socket
>= 0)
336 /* Stop communications */
337 shutdown(sock
->socket
, SHUT_RDWR
);
338 closesocket(sock
->socket
);
343 gnutls_deinit(sock
->session
);
344 #endif /* AICCU_GNUTLS*/
349 /* Connect this client to a server */
350 TLSSOCKET
connect_client(const char *hostname
, const char *service
, int family
, int socktype
)
353 struct addrinfo hints
, *res
, *ressave
;
356 if (!sock
) return NULL
;
358 memset(&hints
, 0, sizeof(struct addrinfo
));
359 hints
.ai_family
= family
;
360 hints
.ai_socktype
= socktype
;
362 if (getaddrinfo(hostname
, service
, &hints
, &res
) != 0)
364 dolog(LOG_ERR
, "Couldn't resolve host %s, service %s\n", hostname
, service
);
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
);
381 freeaddrinfo(ressave
);
383 if (sock
->socket
== -1)
392 TLSSOCKET
listen_server(const char *description
, const char *hostname
, const char *service
, int family
, int socktype
)
394 struct addrinfo hints
, *res
, *ressave
;
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" : "??"),
403 socktype == IPPROTO_UDP ? "UDP" : (socktype == IPPROTO_TCP ? "TCP" : "??"),
407 if (!sock
) return NULL
;
409 memset(&hints
, 0, sizeof(struct addrinfo
));
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. */
417 hints
.ai_flags
= AI_PASSIVE
;
418 hints
.ai_family
= family
;
419 hints
.ai_socktype
= socktype
;
421 n
= getaddrinfo(hostname
, service
, &hints
, &res
);
424 dolog(LOG_ERR
, "[%s] listen_server setup: getaddrinfo error: %s\n", description
, gai_strerror(n
));
431 /* Try to open socket with each address getaddrinfo returned,
432 until we get one valid listening socket. */
435 sock
->socket
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
436 if (!(sock
->socket
< 0))
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
);
446 freeaddrinfo(ressave
);
448 if (sock
->socket
< 0)
450 dolog(LOG_ERR
, "[%s] listen setup: socket error: could not open socket\n", description
);
455 if (listen(sock
->socket
, LISTEN_QUEUE
) == -1)
457 dolog(LOG_ERR
, "[%s] listen setup: socket error: could not listen on socket\n", description
);
462 dolog(LOG_INFO
, "[%s] Listening on [%s]:%s\n", description
, hostname
, service
);
468 * Put a socket into TLS mode
471 bool sock_gotls(TLSSOCKET sock
)
475 if (!sock
) return false;
477 if (sock
->tls_active
)
479 dolog(LOG_ERR
, "Can't go into TLS mode twice!?\n");
483 /* Set the transport */
484 gnutls_transport_set_ptr(sock
->session
, (gnutls_transport_ptr
)sock
->socket
);
486 /* Perform the TLS handshake */
487 ret
= gnutls_handshake(sock
->session
);
490 dolog(LOG_ERR
, "TLS Handshake failed: %s (%d)\n", gnutls_strerror(ret
), ret
);
494 dolog(LOG_DEBUG
, "TLS Handshake completed successfully\n");
496 sock
->tls_active
= true;
501 /* Count the number of fields in <s> */
502 unsigned int countfields(char *s
)
505 if (s
== NULL
) return 0;
506 for (i
=0; s
[i
] != '\0'; i
++) if (s
[i
] == ' ') n
++;
511 * Copy field <n> of string <s> into <buf> with a maximum of buflen
514 bool copyfield(char *s
, unsigned int n
, char *buf
, unsigned int buflen
)
516 unsigned int begin
= 0, i
=0;
518 /* Clear the buffer */
519 memset(buf
, 0, buflen
);
526 /* Find next delimiter */
527 for (; s
[i
] != '\0' && s
[i
] != ' '; i
++);
532 strncpy(buf
, s
+begin
, i
> buflen
? buflen
: i
);
533 /* dolog(LOG_DEBUG, "copyfield() : '%s', begin = %d, len = %d\n", buf, begin, i); */
539 dolog(LOG_WARNING
, "copyfield() - Field %u didn't exist in '%s'\n", n
, s
);
543 bool parseline(char *line
, const char *split
, struct pl_rule
*rules
, void *data
)
546 char *end
= NULL
, *val
= NULL
, *p
= NULL
;
549 /* Chop off \n and \r and white space */
550 p
= &line
[strlen(line
)-1];
551 while ( p
>= line
&& (
555 *p
== ' ')) *p
-- = '\0';
557 /* Ignore comments and emtpy lines */
558 if ( strlen(line
) == 0 ||
561 (line
[0] == '/' && line
[1] == '/'))
566 /* Get the end of the first argument */
568 end
= &line
[strlen(line
)-1];
569 /* Skip until whitespace */
571 strncmp(p
, split
, strlen(split
)) != 0) p
++;
572 /* Terminate this argument */
576 /* Skip whitespace */
581 /* Start of the value */
582 val
= p
+(strlen(split
)-1);
584 /* If starting with quotes, skip until next quote */
585 if (*p
== '"' || *p
== '\'')
588 /* Find next quote */
594 /* Skip the first quote */
597 /* Otherwise it is already terminated above */
599 /* Walk through all the rules */
600 for (r
= 0; rules
[r
].type
!= PLRT_END
; r
++)
602 len
= (int)strlen(rules
[r
].title
);
603 if (strncmp(line
, rules
[r
].title
, len
) != 0) continue;
605 store
= (void *)((char *)data
+ rules
[r
].offset
);
607 switch (rules
[r
].type
)
610 if (*((char **)store
)) free(*((char **)store
));
611 *((char **)store
) = strdup(val
);
615 *((uint32_t *)store
) = atoi(val
);
619 if ( strcmp(val
, "yes") == 0 ||
620 strcmp(val
, "true") == 0)
622 *((bool *)store
) = true;
624 else if (strcmp(val
, "no") == 0 ||
625 strcmp(val
, "false") == 0)
627 *((bool *)store
) = false;
631 dolog(LOG_WARNING
, "Unknown boolean value \"%s\" for option \"%s\"\n", val
, rules
[r
].title
);
636 inet_pton(AF_INET
, val
, store
);
640 inet_pton(AF_INET6
, val
, store
);
653 * sSignature's size MUST be 32 bytes!
655 void MD5String(const char *sString
, char *sSignature
, unsigned int siglen
)
657 struct MD5Context md5c
;
658 unsigned char signature
[16];
661 if (siglen
< 32) return;
663 /* Initialize MD5 structure */
665 /* Calculate MD5 of the string */
666 MD5Update(&md5c
, (unsigned char *)sString
, (unsigned int)strlen(sString
));
667 MD5Final(signature
, &md5c
);
669 memset(sSignature
, 0, siglen
);
671 for (i
=0; i
< sizeof(signature
); i
++)
673 snprintf(&sSignature
[i
*2], 3, "%02x", signature
[i
]);
678 /* AIX doesn't have vsyslog() thus we implement it here */
679 void vsyslog(int priority
, const char *format
, va_list ap
)
682 vsnprintf(buf
, sizeof(buf
), format
, ap
);
683 syslog(priority
, buf
);
688 const char *inet_ntop(int af
, const void *src
, char *dst
, socklen_t cnt
)
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
);
699 else if (af
== AF_INET6
)
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
);
711 int inet_pton(int af
, const char *src
, void *dst
)
713 struct addrinfo hints
, *res
, *ressave
;
715 memset(&hints
, 0, sizeof(struct addrinfo
));
716 hints
.ai_family
= af
;
718 if (getaddrinfo(src
, NULL
, &hints
, &res
) != 0)
720 dolog(LOG_ERR
, "Couldn't resolve host %s\n", src
);
728 /* Check if AF is correct */
729 if (res
->ai_family
!= af
)
735 /* This is the one we want */
736 memcpy(dst
, res
->ai_addr
, af
== AF_INET6
? sizeof(struct in_addr6
) : sizeof(struct in_addr
));
738 /* We only need one */
742 freeaddrinfo(ressave
);