1 /*
2 Copyright (C) 2002-2008 Thomas Ries <tries@gmx.net>
3
4 This file is part of Siproxd.
5
6 Siproxd is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 Siproxd is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Siproxd; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20 #include "config.h"
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <limits.h>
27 #include <time.h>
28 #include <signal.h>
29 #include <string.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 #include <netdb.h>
34 #include <net/if.h>
35 #include <sys/ioctl.h>
36
37 #ifdef HAVE_GETIFADDRS
38 # include <ifaddrs.h>
39 #endif
40
41 #ifdef _SOLARIS2
42 # include <sys/sockio.h>
43 #endif
44
45 #include <sys/types.h>
46 #include <pwd.h>
47
48 #include <osipparser2/osip_parser.h>
49
50 #include "siproxd.h"
51 #include "log.h"
52
53 static char const ident[]="$Id: utils.c 536 2016-02-03 20:02:27Z hb9xar $";
54
55 /* configuration storage */
56 extern struct siproxd_config configuration;
57
58 extern int h_errno;
59
60
61 /*
62 * resolve a hostname and return in_addr
63 * handles its own little DNS cache.
64 *
65 * RETURNS
66 * STS_SUCCESS on success
67 * STS_FAILURE on failure
68 */
get_ip_by_host(char * hostname,struct in_addr * addr)69 int get_ip_by_host(char *hostname, struct in_addr *addr) {
70 int i, j, k, idx;
71 time_t t1, t2;
72 struct hostent *hostentry;
73 #if defined(HAVE_GETHOSTBYNAME_R)
74 struct hostent result_buffer;
75 char tmp[GETHOSTBYNAME_BUFLEN];
76 #endif
77 int error;
78 static struct {
79 time_t expires_timestamp; /* time of expiration */
80 struct in_addr addr; /* IP address or 0.0.0.0 if a bad entry */
81 char error_count; /* counts failed resolution attempts */
82 char bad_entry; /* != 0 if resolving failed */
83 char hostname[HOSTNAME_SIZE+1];
84 } dns_cache[DNS_CACHE_SIZE];
85 static int cache_initialized=0;
86
87 if (hostname == NULL) {
88 ERROR("get_ip_by_host: NULL hostname requested");
89 return STS_FAILURE;
90 }
91
92 if (addr == NULL) {
93 ERROR("get_ip_by_host: NULL in_addr passed");
94 return STS_FAILURE;
95 }
96
97 /* check if passed string is already a plain IPv4 address */
98 if (utils_inet_aton(hostname, addr) > 0) {
99 /* is a plain IPv4 string - return the result directly, no lookup and cache */
100 // DEBUGC(DBCLASS_BABBLE, "DNS lookup - shortcut, hostname is IP string [%s] -> [%s]",
101 // hostname, utils_inet_ntoa(*addr));
102 return STS_SUCCESS;
103 }
104
105 /* first time: initialize DNS cache */
106 if (cache_initialized == 0) {
107 DEBUGC(DBCLASS_DNS, "initializing DNS cache (%i entries)", DNS_CACHE_SIZE);
108 memset(dns_cache, 0, sizeof(dns_cache));
109 cache_initialized=1;
110 }
111
112 time(&t1);
113 /* clean expired entries */
114 for (i=0; i<DNS_CACHE_SIZE; i++) {
115 if (dns_cache[i].hostname[0]=='\0') continue;
116 if ( (dns_cache[i].expires_timestamp) < t1 ) {
117 DEBUGC(DBCLASS_DNS, "cleaning DNS cache (entry %i)", i);
118 memset (&dns_cache[i], 0, sizeof(dns_cache[0]));
119 }
120 }
121
122 /*
123 * search requested entry in cache
124 */
125 idx=0;
126 for (i=0; i<DNS_CACHE_SIZE; i++) {
127 if (dns_cache[i].hostname[0]=='\0') continue; /* empty */
128 if (strcasecmp(hostname, dns_cache[i].hostname) == 0) { /* match */
129 memcpy(addr, &dns_cache[i].addr, sizeof(struct in_addr));
130 if (dns_cache[i].bad_entry) {
131 DEBUGC(DBCLASS_DNS, "DNS lookup - blacklisted from cache: %s",
132 hostname);
133 return STS_FAILURE;
134 }
135 if (dns_cache[i].error_count > 0) {
136 DEBUGC(DBCLASS_DNS, "DNS lookup - previous resolution failed: %s"
137 ", attempt %i", hostname, dns_cache[i].error_count);
138 idx=i;
139 break;
140 }
141 DEBUGC(DBCLASS_BABBLE, "DNS lookup - from cache: %s -> %s",
142 hostname, utils_inet_ntoa(*addr));
143 return STS_SUCCESS;
144 }
145 }
146
147 /* I did not find it in cache, so I have to resolve it */
148 error = 0;
149
150 /* need to deal with reentrant versions of gethostbyname_r()
151 * as we may use threads... */
152 #if defined(HAVE_GETHOSTBYNAME_R)
153
154 /* gethostbyname_r() with 3 arguments (e.g. osf/1) */
155 #if defined(HAVE_FUNC_GETHOSTBYNAME_R_3)
156 gethostbyname_r(hostname, /* the FQDN */
157 &result_buffer, /* the result buffer */
158 &hostentry
159 );
160 if (hostentry == NULL) error = h_errno;
161
162 /* gethostbyname_r() with 5 arguments (e.g. solaris, linux libc5) */
163 #elif defined(HAVE_FUNC_GETHOSTBYNAME_R_5)
164 hostentry = gethostbyname_r(hostname, /* the FQDN */
165 &result_buffer, /* the result buffer */
166 tmp,
167 GETHOSTBYNAME_BUFLEN,
168 &error);
169
170 /* gethostbyname_r() with 6 arguments (e.g. linux glibc) */
171 #elif defined(HAVE_FUNC_GETHOSTBYNAME_R_6)
172 gethostbyname_r(hostname, /* the FQDN */
173 &result_buffer, /* the result buffer */
174 tmp,
175 GETHOSTBYNAME_BUFLEN,
176 &hostentry,
177 &error);
178 #else
179 #error "gethostbyname_r() with 3, 5 or 6 arguments supported only"
180 #endif
181 #elif defined(HAVE_GETHOSTBYNAME)
182 hostentry=gethostbyname(hostname);
183 if (hostentry == NULL) error = h_errno;
184 #else
185 #error "need gethostbyname() or gethostbyname_r()"
186 #endif
187 /* Here I have 'hostentry' and 'error' */
188
189
190 if (hostentry==NULL) {
191 /*
192 * Some errors just tell us that there was no IP resolvable.
193 * From the manpage:
194 * HOST_NOT_FOUND
195 * The specified host is unknown.
196 * NO_ADDRESS or NO_DATA
197 * The requested name is valid but does not have an IP
198 * address.
199 */
200 if ((error == HOST_NOT_FOUND) ||
201 (error == NO_ADDRESS) ||
202 (error == NO_DATA)) {
203 #ifdef HAVE_HSTRERROR
204 DEBUGC(DBCLASS_DNS, "gethostbyname(%s) failed: h_errno=%i [%s]",
205 hostname, h_errno, hstrerror(error));
206 #else
207 DEBUGC(DBCLASS_DNS, "gethostbyname(%s) failed: h_errno=%i",
208 hostname, error);
209 #endif
210 } else {
211 #ifdef HAVE_HSTRERROR
212 ERROR("gethostbyname(%s) failed: h_errno=%i [%s]",
213 hostname, h_errno, hstrerror(h_errno));
214 #else
215 ERROR("gethostbyname(%s) failed: h_errno=%i",hostname, h_errno);
216 #endif
217 }
218 }
219
220 if (hostentry) {
221 memcpy(addr, hostentry->h_addr, sizeof(struct in_addr));
222 DEBUGC(DBCLASS_DNS, "DNS lookup - resolved: %s -> %s",
223 hostname, utils_inet_ntoa(*addr));
224 }
225
226 /* if we already have the entry, skip finding a new empty one */
227 if (idx == 0) {
228 /*
229 * find an empty slot in the cache
230 */
231 j=0;
232 k=0;
233 t1=INT_MAX;
234 t2=INT_MAX;
235 for (i=0; i<DNS_CACHE_SIZE; i++) {
236 if (dns_cache[i].hostname[0]=='\0') break;
237 if ((dns_cache[i].expires_timestamp < t1) &&
238 (dns_cache[i].bad_entry == 0)) {
239 /* remember oldest good entry */
240 t1=dns_cache[i].expires_timestamp;
241 j=i;
242 } else
243 if (dns_cache[i].expires_timestamp < t2) {
244 /* remember oldest bad entry */
245 t2=dns_cache[i].expires_timestamp;
246 k=i;
247 }
248 }
249 /* if no empty slot found, victimize oldest one.
250 * Give preference to the oldest "bad" entry if
251 * one exists */
252 if (i >= DNS_CACHE_SIZE) {
253 if (k > 0) i=k;
254 else i=j;
255 }
256 idx=i;
257 memset(&dns_cache[idx], 0, sizeof(dns_cache[0]));
258 }
259
260 /*
261 * store the result in the cache
262 */
263 DEBUGC(DBCLASS_DNS, "DNS lookup - store into cache, entry %i)", idx);
264 strncpy(dns_cache[idx].hostname, hostname, HOSTNAME_SIZE);
265 dns_cache[idx].expires_timestamp = time(NULL) + DNS_GOOD_AGE;
266 if (hostentry) {
267 memcpy(&dns_cache[idx].addr, addr, sizeof(struct in_addr));
268 dns_cache[idx].error_count = 0;
269 dns_cache[idx].bad_entry = 0;
270 } else {
271 dns_cache[idx].error_count++;
272 DEBUGC(DBCLASS_DNS, "DNS lookup - errcnt=%i", dns_cache[idx].error_count);
273 if (dns_cache[idx].error_count >= DNS_ATTEMPTS) {
274 DEBUGC(DBCLASS_DNS, "DNS lookup - blacklisting entry");
275 dns_cache[idx].expires_timestamp = time(NULL) + DNS_BAD_AGE;
276 dns_cache[idx].bad_entry = 1;
277 }
278 return STS_FAILURE;
279 }
280 return STS_SUCCESS;
281 }
282
283
284 /*
285 * Secure enviroment:
286 * If running as root, put myself into a chroot jail and
287 * change UID/GID to user as requested in config file
288 */
secure_enviroment(void)289 void secure_enviroment (void) {
290 int sts;
291 struct passwd *passwd=NULL;
292
293 DEBUGC(DBCLASS_CONFIG,"running w/uid=%i, euid=%i, gid=%i, egid=%i",
294 (int)getuid(), (int)geteuid(), (int)getgid(), (int)getegid());
295
296 if ((getuid()==0) || (geteuid()==0)) {
297 /*
298 * preparation - after chrooting there will be NOTHING more around
299 */
300 if (configuration.user) passwd=getpwnam(configuration.user);
301
302 /*
303 * change root directory into chroot jail
304 */
305 if (configuration.chrootjail) {
306 /* !!!
307 * Before chrooting I must at least once trigger the resolver
308 * as it loads some dynamic libraries. Once chrootet
309 * these libraries will *not* be found and gethostbyname()
310 * calls will simply fail (return NULL pointer and h_errno=0).
311 * Also (at least for FreeBSD) syslog() needs to be called
312 * before chroot()ing - this is done in main() by an INFO().
313 * Took me a while to figure THIS one out
314 */
315 struct in_addr dummy;
316 get_ip_by_host("localhost", &dummy);
317 DEBUGC(DBCLASS_CONFIG,"chrooting to %s",
318 configuration.chrootjail);
319 sts = chroot(configuration.chrootjail);
320 if (sts != 0) DEBUGC(DBCLASS_CONFIG,"chroot(%s) failed: %s",
321 configuration.chrootjail, strerror(errno));
322 sts=chdir("/");
323 }
324
325 /*
326 * change user ID and group ID
327 */
328 if (passwd) {
329 DEBUGC(DBCLASS_CONFIG,"changing uid/gid to %s",
330 configuration.user);
331 sts = setgid(passwd->pw_gid);
332 DEBUGC(DBCLASS_CONFIG,"changed gid to %i - %s",
333 (int)passwd->pw_gid, (sts==0)?"Ok":"Failed");
334
335 sts = setegid(passwd->pw_gid);
336 DEBUGC(DBCLASS_CONFIG,"changed egid to %i - %s",
337 (int)passwd->pw_gid, (sts==0)?"Ok":"Failed");
338
339 sts = seteuid(passwd->pw_uid);
340 DEBUGC(DBCLASS_CONFIG,"changed euid to %i - %s",
341 (int)passwd->pw_uid, (sts==0)?"Ok":"Failed");
342 }
343 }
344 }
345
346
347 /*
348 * get_interface_ip:
349 * fetches own IP address by interface INBOUND/OUTBOUND
350 * takes into account a possible outbound_host setting.
351 *
352 * STS_SUCCESS on returning a valid IP and interface is UP
353 * STS_FAILURE if interface is DOWN or other problem
354 */
get_interface_ip(int interface,struct in_addr * retaddr)355 int get_interface_ip(int interface, struct in_addr *retaddr) {
356 int sts=STS_FAILURE;
357
358 if ((interface == IF_OUTBOUND) &&
359 (configuration.outbound_host) &&
360 (strcmp(configuration.outbound_host, "")!=0)) {
361 DEBUGC(DBCLASS_DNS, "fetching outbound IP by HOSTNAME");
362 if (retaddr) {
363 sts = get_ip_by_host(configuration.outbound_host, retaddr);
364 } else {
365 sts = STS_SUCCESS;
366 }
367
368 } else {
369 sts = get_interface_real_ip(interface, retaddr);
370 }
371
372 return sts;
373 }
374
375
376 /*
377 * get_interface_real_ip:
378 * fetches the real IP address of my interface INBOUND/OUTBOUND
379 *
380 * STS_SUCCESS on returning a valid IP and interface is UP
381 * STS_FAILURE if interface is DOWN or other problem
382 */
get_interface_real_ip(int interface,struct in_addr * retaddr)383 int get_interface_real_ip(int interface, struct in_addr *retaddr) {
384 int sts=STS_FAILURE;
385 char *tmp=NULL;
386
387 if (interface == IF_INBOUND) {
388 tmp = configuration.inbound_if;
389 } else if (interface == IF_OUTBOUND) {
390 tmp = configuration.outbound_if;
391 }
392
393 if (tmp && (strcmp(tmp, "")!=0)) {
394 DEBUGC(DBCLASS_DNS, "fetching interface IP by INTERFACE [%i]", interface);
395 sts = get_ip_by_ifname(tmp, retaddr);
396 if (sts != STS_SUCCESS) {
397 ERROR("can't find interface %s - configuration error?", tmp);
398 }
399
400 } else {
401 ERROR("Don't know what interface to look for - configuration error?");
402 }
403
404 return sts;
405 }
406
407
408 /*
409 * get_ip_by_ifname:
410 * fetches own IP address by its interface name
411 *
412 * STS_SUCCESS on returning a valid IP and interface is UP
413 * STS_FAILURE if interface is DOWN or other problem
414 */
get_ip_by_ifname(char * ifname,struct in_addr * retaddr)415 int get_ip_by_ifname(char *ifname, struct in_addr *retaddr) {
416 struct in_addr ifaddr; /* resulting IP */
417 int i, j;
418 int ifflags=0, isup=0;
419 time_t t;
420 static struct {
421 time_t timestamp;
422 struct in_addr ifaddr; /* IP */
423 int isup; /* interface is UP */
424 char ifname[IFNAME_SIZE+1];
425 } ifaddr_cache[IFADR_CACHE_SIZE];
426 static int cache_initialized=0;
427 #ifdef HAVE_GETIFADDRS
428 struct ifaddrs *ifa;
429 struct ifaddrs *ifa_list;
430 #else
431 struct ifreq ifr;
432 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
433 int sockfd;
434 #endif
435
436 if (ifname == NULL) {
437 WARN("get_ip_by_ifname: got NULL ifname passed - please check config"
438 "file ('if_inbound' and 'if_outbound')");
439 return STS_FAILURE;
440 }
441
442 /* first time: initialize ifaddr cache */
443 if (cache_initialized == 0) {
444 DEBUGC(DBCLASS_DNS, "initializing ifaddr cache (%i entries)",
445 IFADR_CACHE_SIZE);
446 memset(ifaddr_cache, 0, sizeof(ifaddr_cache));
447 cache_initialized=1;
448 }
449
450 if (retaddr) memset(retaddr, 0, sizeof(struct in_addr));
451
452 time(&t);
453 /* clean expired entries */
454 for (i=0; i<IFADR_CACHE_SIZE; i++) {
455 if (ifaddr_cache[i].ifname[0]=='\0') continue;
456 if ( (ifaddr_cache[i].timestamp+IFADR_MAX_AGE) < t ) {
457 DEBUGC(DBCLASS_DNS, "cleaning ifaddr cache (entry %i)", i);
458 memset (&ifaddr_cache[i], 0, sizeof(ifaddr_cache[0]));
459 }
460 }
461
462 /*
463 * search requested entry in cache
464 */
465 for (i=0; i<IFADR_CACHE_SIZE; i++) {
466 if (ifaddr_cache[i].ifname[0]=='\0') continue;
467 if (strcmp(ifname, ifaddr_cache[i].ifname) == 0) { /* match */
468 if (retaddr) memcpy(retaddr, &ifaddr_cache[i].ifaddr,
469 sizeof(struct in_addr));
470 DEBUGC(DBCLASS_DNS, "ifaddr lookup - from cache: %s -> %s %s",
471 ifname, utils_inet_ntoa(ifaddr_cache[i].ifaddr),
472 (ifaddr_cache[i].isup)? "UP":"DOWN");
473 return (ifaddr_cache[i].isup)? STS_SUCCESS: STS_FAILURE;
474 } /* if */
475 } /* for i */
476
477 /* not found in cache, go and get it */
478
479 #ifdef HAVE_GETIFADDRS
480 if (getifaddrs(&ifa_list)) {
481 ERROR("Error in getifaddrs: %s",strerror(errno));
482 return STS_FAILURE;
483 }
484
485 i=0; /* use "found" marker */
486 for (ifa = ifa_list; ifa != NULL; ifa = ifa->ifa_next) {
487 DEBUGC(DBCLASS_BABBLE,"getifaddrs - %s / %s, ifa_addr=%p, addrfamily=%i",
488 ifname, ifa->ifa_name,ifa->ifa_addr,
489 (ifa->ifa_addr)?ifa->ifa_addr->sa_family:-1);
490
491 if (ifa && ifa->ifa_name && ifa->ifa_addr &&
492 ifa->ifa_addr->sa_family == AF_INET &&
493 strcmp(ifa->ifa_name, ifname) == 0) {
494 /* found the entry */
495 i=1;
496 memcpy(&ifaddr, &((struct sockaddr_in*)ifa->ifa_addr)->sin_addr, sizeof(struct in_addr));
497 ifflags=ifa->ifa_flags;
498 DEBUGC(DBCLASS_BABBLE,"getifaddrs - MATCH, sin_addr=%s",
499 utils_inet_ntoa(ifaddr));
500 break;
501 }
502 }
503 freeifaddrs(ifa_list);
504
505 if (i==0) {
506 DEBUGC(DBCLASS_DNS,"Interface %s not found.", ifname);
507 return STS_FAILURE;
508 }
509
510 #else
511 memset(&ifr, 0, sizeof(ifr));
512
513 if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
514 ERROR("Error in socket: %s",strerror(errno));
515 return STS_FAILURE;
516 }
517
518 /*&&&*/DEBUGC(DBCLASS_BABBLE,"&&&6 ifname=0x%p",ifname);
519 strcpy(ifr.ifr_name, ifname);
520 sin->sin_family = AF_INET;
521
522 /* get interface flags */
523 if(ioctl(sockfd, SIOCGIFFLAGS, &ifr) != 0) {
524 ERROR("Error in ioctl SIOCGIFFLAGS: %s [%s]",
525 strerror(errno), ifname);
526 close(sockfd);
527 return STS_FAILURE;
528 }
529 ifflags=ifr.ifr_flags;
530 /*&&&*/DEBUGC(DBCLASS_BABBLE,"&&&7 ifname=0x%p",ifname);
531
532 /* get address */
533 if(ioctl(sockfd, SIOCGIFADDR, &ifr) != 0) {
534 ERROR("Error in ioctl SIOCGIFADDR: %s (interface %s)",
535 strerror(errno), ifname);
536 close(sockfd);
537 return STS_FAILURE;
538 }
539
540 /*&&&*/DEBUGC(DBCLASS_BABBLE,"&&&8 ifname=0x%p",ifname);
541 memcpy(&ifaddr, &sin->sin_addr, sizeof(struct in_addr));
542 /*&&&*/DEBUGC(DBCLASS_BABBLE,"&&&9 ifname=0x%p",ifname);
543 close(sockfd);
544 #endif
545
546 if (ifflags & IFF_UP) isup=1;
547 else isup=0;
548
549 DEBUGC(DBCLASS_DNS, "get_ip_by_ifname: if %s has IP:%s (flags=%x) %s",
550 ifname, utils_inet_ntoa(ifaddr), ifflags,
551 (isup)? "UP":"DOWN");
552
553 /*
554 *find an empty slot in the cache
555 */
556 j=0;
557 for (i=0; i<IFADR_CACHE_SIZE; i++) {
558 if (ifaddr_cache[i].ifname[0]=='\0') break;
559 if (ifaddr_cache[i].timestamp < t) {
560 /* remember oldest entry */
561 t=ifaddr_cache[i].timestamp;
562 j=i;
563 }
564 }
565 /* if no empty slot found, take oldest one */
566 if (i >= IFADR_CACHE_SIZE) i=j;
567
568 /*
569 * store the result in the cache
570 */
571 DEBUGC(DBCLASS_DNS, "ifname lookup - store into cache, entry %i)", i);
572 memset(&ifaddr_cache[i], 0, sizeof(ifaddr_cache[0]));
573 strncpy(ifaddr_cache[i].ifname, ifname, IFNAME_SIZE);
574 ifaddr_cache[i].timestamp=t;
575 memcpy(&ifaddr_cache[i].ifaddr, &ifaddr, sizeof(struct in_addr));
576 ifaddr_cache[i].isup=isup;
577
578 if (retaddr) memcpy(retaddr, &ifaddr, sizeof(struct in_addr));
579
580 return (isup)? STS_SUCCESS : STS_FAILURE;
581 }
582
583
584 /*
585 * utils_inet_ntoa:
586 * implements an inet_ntoa()
587 *
588 * Returns pointer to a STATIC character string.
589 * NOte: BE AWARE OF THE STATIC NATURE of the string! Never pass it as
590 * calling argument to a function and use it immediately or strcpy()
591 * it into a buffer.
592 * !! Any subsequent call to this function will DESTROY the previous
593 * !! value - and may result in very strange effects like magically
594 * !! changing variable value (that has been passed to a function)
595 * Been there, seen that, so TAKE CARE!
596 */
utils_inet_ntoa(struct in_addr in)597 char *utils_inet_ntoa(struct in_addr in) {
598 #if defined(HAVE_INET_NTOP)
599 static char string[INET_ADDRSTRLEN];
600 if ((inet_ntop(AF_INET, &in, string, INET_ADDRSTRLEN)) == NULL) {
601 ERROR("inet_ntop() failed: %s",strerror(errno));
602 string[0]='\0';
603 }
604 return string;
605 #elif defined(HAVE_INET_NTOA)
606 return inet_ntoa(in);
607 #else
608 #error "need inet_ntop() or inet_ntoa()"
609 #endif
610 }
611
612
613 /*
614 * utils_inet_aton:
615 * implements an inet_aton()
616 *
617 * converts the string in *cp and stores it into inp
618 * Returns > 0 on success
619 */
utils_inet_aton(const char * cp,struct in_addr * inp)620 int utils_inet_aton(const char *cp, struct in_addr *inp) {
621 #if defined(HAVE_INET_PTON)
622 return inet_pton (AF_INET, cp, inp);
623 #elif defined(HAVE_INET_ATON)
624 return inet_aton(cp, inp);
625 #else
626 #error "need inet_pton() or inet_aton()"
627 #endif
628 }
629
630 /*
631 * Create the PID file
632 */
createpidfile(char * pidfilename)633 int createpidfile(char *pidfilename) {
634 FILE *f = NULL;
635 int sts;
636 DEBUGC(DBCLASS_CONFIG,"creating PID file [%s]", pidfilename);
637 sts=unlink(pidfilename);
638 if ((sts==0) || (errno == ENOENT)) {
639 if ((f=fopen(pidfilename, "w"))) {
640 fprintf(f,"%i\n",(int)getpid());
641 fclose(f);
642 } else {
643 WARN("couldn't create new PID file: %s", strerror(errno));
644 return STS_FAILURE;
645 }
646 } else {
647 WARN("couldn't delete old PID file: %s", strerror(errno));
648 return STS_FAILURE;
649 }
650 return STS_SUCCESS;
651 }
652
653
654 /*
655 * compare_client_id:
656 * Compares two client_id_t structures. If both have the Contact item
657 * defined (not NULL), then compare it and return.
658 * If one (or both) do NOT have the contact item defined, then
659 * fall back on comparing the from_ip (IP address).
660 *
661 * returns:
662 * STS_SUCCESS on match
663 * STS_FAILURE on no match
664 */
compare_client_id(client_id_t cid1,client_id_t cid2)665 int compare_client_id(client_id_t cid1, client_id_t cid2) {
666
667 /* Prio 1: Contact - if present in both structures */
668 if ((cid1.idstring[0] != '\0') && (cid2.idstring[0] != '\0')) {
669 if (strncmp(cid1.idstring, cid2.idstring, CLIENT_ID_SIZE) == 0) {
670 DEBUGC(DBCLASS_BABBLE, "compare_client_id: contact match [%s]",
671 cid1.idstring);
672 return STS_SUCCESS;
673 }
674 DEBUGC(DBCLASS_BABBLE, "compare_client_id: contact NO match [%s<->%s]",
675 cid1.idstring, cid2.idstring);
676 return STS_FAILURE;
677 }
678
679 /* Prio 2: IP (always present) - fallback, if no ID string present. */
680 if (memcmp(&cid1.from_ip, &cid2.from_ip, sizeof(struct in_addr)) == 0) {
681 DEBUGC(DBCLASS_BABBLE, "compare_client_id: IP match [%s]",
682 utils_inet_ntoa(cid1.from_ip));
683 return STS_SUCCESS;
684 }
685
686 DEBUGC(DBCLASS_BABBLE, "compare_client_id: no match");
687 return STS_FAILURE;
688 }
689
690
691 /*
692 * check a sockaddr_in structure for bein zero / non-zero
693 */
is_empty_sockaddr(struct sockaddr_in * sockaddr)694 int is_empty_sockaddr(struct sockaddr_in *sockaddr) {
695 int i;
696 char *p=(char*)sockaddr;
697
698 for (i=0; i < sizeof(struct sockaddr_in); i++) {
699 if (p[i] != 0x00) { return STS_FAILURE; }
700 }
701 return STS_SUCCESS;
702 }
703