1 /*
2  * $Id: helper.c 397 2006-01-28 21:11:50Z calrissian $
3  *
4  * Copyright (C) 2002-2004 Fhg Fokus
5  * Copyright (C) 2004-2005 Nils Ohlmeier
6  *
7  * This file belongs to sipsak, a free sip testing tool.
8  *
9  * sipsak is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * sipsak is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  */
19 #include "sipsak.h"
20 
21 #ifdef HAVE_NETDB_H
22 # include <netdb.h>
23 #endif
24 #ifdef HAVE_UNISTD_H
25 # ifdef HAVE_SYS_TYPES_H
26 #  include <sys/types.h>
27 # endif
28 # include <unistd.h>
29 #endif
30 #ifdef HAVE_SYS_UTSNAME_H
31 # include <sys/utsname.h>
32 #endif
33 #ifdef HAVE_CTYPE_H
34 # include <ctype.h>
35 #endif
36 #ifdef HAVE_ARPA_INET_H
37 # include <arpa/inet.h>
38 #endif
39 #ifdef HAVE_NETINET_IN_H
40 # include <netinet/in.h>
41 #endif
42 #ifdef HAVE_RULI_H
43 # include <ruli.h>
44 #endif
45 #ifdef HAVE_ERRNO_H
46 # include <errno.h>
47 #endif
48 #ifdef HAVE_CARES_H
49 # ifdef HAVE_ARPA_NAMESER_H
50 #  include <arpa/nameser.h>
51 # endif
52 # include <ares.h>
53 # ifndef NS_RRFIXEDSZ
54 #  define NS_RRFIXEDSZ 10
55 #  define NS_QFIXEDSZ  4
56 #  define NS_HFIXEDSZ  12
57 # endif
58  int caport;
59  unsigned long caadr;
60  char *ca_tmpname;
61  ares_channel channel;
62 
63 #endif // HAVE_CARES_H
64 
65 #include "helper.h"
66 #include "exit_code.h"
67 
68 /* returns 1 if the string an IP address otherwise zero */
is_ip(char * str)69 int is_ip(char *str) {
70 	int i = 0;
71 	int dotcount = 0;
72 
73 	/*try understanding if this is a valid ip address
74 	we are skipping the values of the octets specified here.
75 	for instance, this code will allow 952.0.320.567 through*/
76 	while (*str != '\0')
77 	{
78 		for (i = 0; i < 3; i++, str++)
79 			if (isdigit((int)*str) == 0)
80 				break;
81 		if (*str != '.')
82 			break;
83 		str++;
84 		dotcount++;
85 	}
86 
87 	/* three dots with upto three digits in before, between and after ? */
88 	if (dotcount == 3 && i > 0 && i <= 3)
89 		return 1;
90 	else
91 		return 0;
92 }
93 
94 /* take either a dot.decimal string of ip address or a
95 domain name and returns a NETWORK ordered long int containing
96 the address. i chose to internally represent the address as long for speedier
97 comparisions.
98 
99 any changes to getaddress have to be patched back to the net library.
100 contact: farhan@hotfoon.com
101 
102   returns zero if there is an error.
103   this is convenient as 0 means 'this' host and the traffic of
104   a badly behaving dns system remains inside (you send to 0.0.0.0)
105 */
106 
getaddress(char * host)107 unsigned long getaddress(char *host) {
108 	struct hostent* pent;
109 	long l, *lp;
110 
111 	if (is_ip(host))
112 		return inet_addr(host);
113 
114 	/* try the system's own resolution mechanism for dns lookup:
115 	 required only for domain names.
116 	 inspite of what the rfc2543 :D Using SRV DNS Records recommends,
117 	 we are leaving it to the operating system to do the name caching.
118 
119 	 this is an important implementational issue especially in the light
120 	 dynamic dns servers like dynip.com or dyndns.com where a dial
121 	 ip address is dynamically assigned a sub domain like farhan.dynip.com
122 
123 	 although expensive, this is a must to allow OS to take
124 	 the decision to expire the DNS records as it deems fit.
125 	*/
126 	pent = gethostbyname(host);
127 	if (!pent) {
128 		printf("'%s' is unresolveable\n", host);
129 		exit_code(2);
130 	}
131 	lp = (long *) (pent->h_addr);
132 	l = *lp;
133 	return l;
134 }
135 
136 #ifdef HAVE_CARES_H
parse_rr(const unsigned char * aptr,const unsigned char * abuf,int alen)137 static const unsigned char *parse_rr(const unsigned char *aptr, const unsigned char *abuf, int alen) {
138 	char *name;
139 	long len;
140 	int status, type, dnsclass, dlen;
141 	struct in_addr addr;
142 
143 #ifdef DEBUG
144 	printf("ca_tmpname: %s\n", ca_tmpname);
145 #endif
146 	status = ares_expand_name(aptr, abuf, alen, &name, &len);
147 	if (status != ARES_SUCCESS) {
148 		printf("error: failed to expand query name\n");
149 		exit_code(2);
150 	}
151 	aptr += len;
152 	if (aptr + NS_RRFIXEDSZ > abuf + alen) {
153 		printf("error: not enough data in DNS answer 1\n");
154 		free(name);
155 		return NULL;
156 	}
157 	type = DNS_RR_TYPE(aptr);
158 	dnsclass = DNS_RR_CLASS(aptr);
159 	dlen = DNS_RR_LEN(aptr);
160 	aptr += NS_RRFIXEDSZ;
161 	if (aptr + dlen > abuf + alen) {
162 		printf("error: not enough data in DNS answer 2\n");
163 		free(name);
164 		return NULL;
165 	}
166 	if (dnsclass != CARES_CLASS_C_IN) {
167 		printf("error: unsupported dnsclass (%i) in DNS answer\n", dnsclass);
168 		free(name);
169 		return NULL;
170 	}
171 	if ((ca_tmpname == NULL && type != CARES_TYPE_SRV) ||
172 		(ca_tmpname != NULL &&
173 		 	(type != CARES_TYPE_A && type != CARES_TYPE_CNAME))) {
174 		printf("error: unsupported DNS response type (%i)\n", type);
175 		free(name);
176 		return NULL;
177 	}
178 	if (type == CARES_TYPE_SRV) {
179 		free(name);
180 		caport = DNS__16BIT(aptr + 4);
181 #ifdef DEBUG
182 		printf("caport: %i\n", caport);
183 #endif
184 		status = ares_expand_name(aptr + 6, abuf, alen, &name, &len);
185 		if (status != ARES_SUCCESS) {
186 			printf("error: failed to expand SRV name\n");
187 			return NULL;
188 		}
189 #ifdef DEBUG
190 		printf("SRV name: %s\n", name);
191 #endif
192 		if (is_ip(name)) {
193 			caadr = inet_addr(name);
194 			free(name);
195 		}
196 		else {
197 			ca_tmpname = name;
198 		}
199 	}
200 	else if (type == CARES_TYPE_CNAME) {
201 		if (STRNCASECMP(ca_tmpname, name, strlen(ca_tmpname)) == 0) {
202 			ca_tmpname = malloc(strlen(name));
203 			if (ca_tmpname == NULL) {
204 				printf("error: failed to allocate memory\n");
205 				exit_code(2);
206 			}
207 			strcpy(ca_tmpname, name);
208 		}
209 		free(name);
210 	}
211 	else if (type == CARES_TYPE_A) {
212 		if (dlen == 4 && STRNCASECMP(ca_tmpname, name, strlen(ca_tmpname)) == 0) {
213 			memcpy(&addr, aptr, sizeof(struct in_addr));
214 			caadr = addr.s_addr;
215 		}
216 		free(name);
217 	}
218 	return aptr + dlen;
219 }
220 
skip_rr(const unsigned char * aptr,const unsigned char * abuf,int alen)221 static const unsigned char *skip_rr(const unsigned char *aptr, const unsigned char *abuf, int alen) {
222 	int status, dlen;
223 	long len;
224 	char *name;
225 
226 #ifdef DEBUG
227 	printf("skipping rr section...\n");
228 #endif
229 	status = ares_expand_name(aptr, abuf, alen, &name, &len);
230 	aptr += len;
231 	dlen = DNS_RR_LEN(aptr);
232 	aptr += NS_RRFIXEDSZ;
233 	aptr += dlen;
234 	free(name);
235 	return aptr;
236 }
237 
skip_query(const unsigned char * aptr,const unsigned char * abuf,int alen)238 static const unsigned char *skip_query(const unsigned char *aptr, const unsigned char *abuf, int alen) {
239 	int status;
240 	long len;
241 	char *name;
242 
243 #ifdef DEBUG
244 	printf("skipping query section...\n");
245 #endif
246 	status = ares_expand_name(aptr, abuf, alen, &name, &len);
247 	aptr += len;
248 	aptr += NS_QFIXEDSZ;
249 	free(name);
250 	return aptr;
251 }
252 
cares_callback(void * arg,int status,unsigned char * abuf,int alen)253 static void cares_callback(void *arg, int status, unsigned char *abuf, int alen) {
254 	int i;
255 	unsigned int ancount, nscount, arcount;
256 	const unsigned char *aptr;
257 
258 #ifdef DEBUG
259 	printf("cares_callback: status=%i, alen=%i\n", status, alen);
260 #endif
261 	if (status != ARES_SUCCESS) {
262 		if (verbose > 1)
263 			printf("ares failed: %s\n", ares_strerror(status));
264 		return;
265 	}
266 
267 	ancount = DNS_HEADER_ANCOUNT(abuf);
268 	nscount = DNS_HEADER_NSCOUNT(abuf);
269 	arcount = DNS_HEADER_ARCOUNT(abuf);
270 
271 #ifdef DEBUG
272 	printf("ancount: %i, nscount: %i, arcount: %i\n", ancount, nscount, arcount);
273 #endif
274 
275 	/* safety check */
276 	if (alen < NS_HFIXEDSZ)
277 		return;
278 	aptr = abuf + NS_HFIXEDSZ;
279 
280 	aptr = skip_query(aptr, abuf, alen);
281 
282 	for (i = 0; i < ancount && caadr == 0; i++) {
283 		if (ca_tmpname == NULL)
284 			aptr = parse_rr(aptr, abuf, alen);
285 		else
286 			aptr = skip_rr(aptr, abuf, alen);
287 	}
288 	if (caadr == 0) {
289 		for (i = 0; i < nscount; i++) {
290 			aptr = skip_rr(aptr, abuf, alen);
291 		}
292 		for (i = 0; i < arcount && caadr == 0; i++) {
293 			aptr = parse_rr(aptr, abuf, alen);
294 		}
295 	}
296 }
297 
srv_ares(char * host,int * port,char * srv)298 inline unsigned long srv_ares(char *host, int *port, char *srv) {
299 	int nfds, count, srvh_len;
300 	char *srvh;
301 	fd_set read_fds, write_fds;
302 	struct timeval *tvp, tv;
303 
304 	caport = 0;
305 	caadr = 0;
306 	ca_tmpname = NULL;
307 #ifdef DEBUG
308 	printf("!!! ARES query !!!\n");
309 #endif
310 
311 	srvh_len = strlen(host) + strlen(srv) + 2;
312 	srvh = malloc(srvh_len);
313 	if (srvh == NULL) {
314 		printf("error: failed to allocate memory (%i) for ares query\n", srvh_len);
315 		exit_code(2);
316 	}
317 	memset(srvh, 0, srvh_len);
318 	strncpy(srvh, srv, strlen(srv));
319 	memcpy(srvh + strlen(srv), ".", 1);
320 	strcpy(srvh + strlen(srv) + 1, host);
321 #ifdef DEBUG
322 	printf("hostname: '%s', len: %i\n", srvh, srvh_len);
323 #endif
324 
325 	ares_query(channel, srvh, CARES_CLASS_C_IN, CARES_TYPE_SRV, cares_callback, (char *) NULL);
326 #ifdef DEBUG
327 	printf("after ares_query\n");
328 #endif
329 	/* wait for query to complete */
330 	while (1) {
331 		FD_ZERO(&read_fds);
332 		FD_ZERO(&write_fds);
333 		nfds = ares_fds(channel, &read_fds, &write_fds);
334 		if (nfds == 0)
335 			break;
336 		tvp = ares_timeout(channel, NULL, &tv);
337 		count = select(nfds, &read_fds, &write_fds, NULL, tvp);
338 		if (count < 0 && errno != EINVAL) {
339 			perror("ares select");
340 			exit_code(2);
341 		}
342 		ares_process(channel, &read_fds, &write_fds);
343 	}
344 #ifdef DEBUG
345 	printf("end of while\n");
346 #endif
347 	*port = caport;
348 	if (caadr == 0 && ca_tmpname != NULL) {
349 		caadr = getaddress(ca_tmpname);
350 	}
351 	if (ca_tmpname != NULL)
352 		free(ca_tmpname);
353 	free(srvh);
354 	return caadr;
355 }
356 #endif // HAVE_CARES_H
357 
358 #ifdef HAVE_RULI_H
srv_ruli(char * host,int * port,char * srv)359 inline unsigned long srv_ruli(char *host, int *port, char *srv) {
360 	int srv_code;
361 	int ruli_opts = RULI_RES_OPT_SEARCH | RULI_RES_OPT_SRV_NOINET6 | RULI_RES_OPT_SRV_NOSORT6 | RULI_RES_OPT_SRV_NOFALL;
362 #ifdef RULI_RES_OPT_SRV_CNAME
363 	ruli_opts |= RULI_RES_OPT_SRV_CNAME;
364 #endif
365 
366 	ruli_sync_t *sync_query = ruli_sync_query(srv, host, *port, ruli_opts);
367 
368 	/* sync query failure? */
369 	if (!sync_query) {
370 		printf("DNS SRV lookup failed for: %s\n", host);
371 		exit_code(2);
372 	}
373 
374 	srv_code = ruli_sync_srv_code(sync_query);
375 	/* timeout? */
376 	if (srv_code == RULI_SRV_CODE_ALARM) {
377 		printf("Timeout during DNS SRV lookup for: %s\n", host);
378 		ruli_sync_delete(sync_query);
379 		exit_code(2);
380 	}
381 	/* service provided? */
382 	else if (srv_code == RULI_SRV_CODE_UNAVAILABLE) {
383 		printf("SRV service not provided for: %s\n", host);
384 		ruli_sync_delete(sync_query);
385 		exit_code(2);
386 	}
387 	else if (srv_code) {
388 		int rcode = ruli_sync_rcode(sync_query);
389 		if (verbose > 1)
390 			printf("SRV query failed for: %s, srv_code=%d, rcode=%d\n", host, srv_code, rcode);
391 		ruli_sync_delete(sync_query);
392 		return 0;
393 	}
394 
395 	ruli_list_t *srv_list = ruli_sync_srv_list(sync_query);
396 
397 	int srv_list_size = ruli_list_size(srv_list);
398 
399 	if (srv_list_size < 1) {
400 		if (verbose > 1)
401 			printf("No SRV record: %s.%s\n", srv, host);
402 		return 0;
403 	}
404 
405 	ruli_srv_entry_t *entry = (ruli_srv_entry_t *) ruli_list_get(srv_list, 0);
406 	ruli_list_t *addr_list = &entry->addr_list;
407 	int addr_list_size = ruli_list_size(addr_list);
408 
409 	if (addr_list_size < 1) {
410 		printf("missing addresses in SRV lookup for: %s\n", host);
411 		ruli_sync_delete(sync_query);
412 		exit_code(2);
413 	}
414 
415 	*port = entry->port;
416 	ruli_addr_t *addr = (ruli_addr_t *) ruli_list_get(addr_list, 0);
417 	return addr->addr.ipv4.s_addr;
418 }
419 #endif // HAVE_RULI_H
420 
getsrvaddress(char * host,int * port,char * srv)421 unsigned long getsrvaddress(char *host, int *port, char *srv) {
422 #ifdef HAVE_RULI_H
423 	return srv_ruli(host, port, srv);
424 #else
425 # ifdef HAVE_CARES_H // HAVE_RULI_H
426 	return srv_ares(host, port, srv);
427 # else // HAVE_CARES_H
428 	return 0;
429 # endif
430 #endif
431 }
432 
433 /* Finds the SRV records for the given host. It returns the target IP
434  * address and fills the port and transport if a suitable SRV record
435  * exists. Otherwise it returns 0. The function follows 3263: first
436  * TLS, then TCP and finally UDP. */
getsrvadr(char * host,int * port,unsigned int * transport)437 unsigned long getsrvadr(char *host, int *port, unsigned int *transport) {
438 	unsigned long adr = 0;
439 
440 #ifdef HAVE_SRV
441 	int srvport = 5060;
442 
443 #ifdef HAVE_CARES_H
444 	int status;
445 	int optmask = ARES_OPT_FLAGS;
446 	struct ares_options options;
447 
448 	options.flags = ARES_FLAG_NOCHECKRESP;
449 	options.servers = NULL;
450 	options.nservers = 0;
451 
452 	status = ares_init_options(&channel, &options, optmask);
453 	if (status != ARES_SUCCESS) {
454 		printf("error: failed to initialize ares\n");
455 		exit_code(2);
456 	}
457 #endif
458 
459 #ifdef WITH_TLS_TRANSP
460 	adr = getsrvaddress(host, &srvport, SRV_SIP_TLS);
461 	if (adr != 0) {
462 		*transport = SIP_TLS_TRANSPORT;
463 		if (verbose > 1)
464 			printf("using SRV record: %s.%s:%i\n", SRV_SIP_TLS, host, srvport);
465 		printf("TLS transport not yet supported\n");
466 		exit_code(2);
467 	}
468 	else {
469 #endif
470 		adr = getsrvaddress(host, &srvport, SRV_SIP_TCP);
471 		if (adr != 0) {
472 			*transport = SIP_TCP_TRANSPORT;
473 			if (verbose > 1)
474 				printf("using SRV record: %s.%s:%i\n", SRV_SIP_TCP, host, srvport);
475 		}
476 		else {
477 			adr = getsrvaddress(host, &srvport, SRV_SIP_UDP);
478 			if (adr != 0) {
479 				*transport = SIP_UDP_TRANSPORT;
480 				if (verbose > 1)
481 					printf("using SRV record: %s.%s:%i\n", SRV_SIP_UDP, host, srvport);
482 			}
483 		}
484 #ifdef WITH_TLS_TRANSP
485 	}
486 #endif
487 
488 #ifdef HAVE_CARES_H
489 	ares_destroy(channel);
490 #endif
491 
492 	*port = srvport;
493 #endif // HAVE_SRV
494 	return adr;
495 }
496 
497 /* because the full qualified domain name is needed by many other
498    functions it will be determined by this function.
499 */
get_fqdn()500 void get_fqdn(){
501 	char hname[100], dname[100], hlp[18];
502 	size_t namelen=100;
503 	struct hostent* he;
504 	struct utsname un;
505 
506 	memset(&hname, 0, sizeof(hname));
507 	memset(&dname, 0, sizeof(dname));
508 	memset(&hlp, 0, sizeof(hlp));
509 
510 	if (hostname) {
511 		strncpy(fqdn, hostname, FQDN_SIZE);
512 		strncpy(hname, hostname, 100);
513 	}
514 	else {
515 		if ((uname(&un))==0) {
516 			strncpy(hname, un.nodename, 100);
517 		}
518 		else {
519 			if (gethostname(&hname[0], namelen) < 0) {
520 				fprintf(stderr, "error: cannot determine hostname\n");
521 				exit_code(2);
522 			}
523 		}
524 #ifdef HAVE_GETDOMAINNAME
525 		/* a hostname with dots should be a domainname */
526 		if ((strchr(hname, '.'))==NULL) {
527 			if (getdomainname(&dname[0], namelen) < 0) {
528 				fprintf(stderr, "error: cannot determine domainname\n");
529 				exit_code(2);
530 			}
531 			if (strcmp(&dname[0],"(none)")!=0)
532 				snprintf(fqdn, FQDN_SIZE, "%s.%s", hname, dname);
533 		}
534 		else {
535 			strncpy(fqdn, hname, FQDN_SIZE);
536 		}
537 #endif
538 	}
539 
540 	if (!(numeric == 1 && is_ip(fqdn))) {
541 		he=gethostbyname(hname);
542 		if (he) {
543 			if (numeric == 1) {
544 				snprintf(hlp, 15, "%s", inet_ntoa(*(struct in_addr *) he->h_addr_list[0]));
545 				strncpy(fqdn, hlp, FQDN_SIZE);
546 			}
547 			else {
548 				if ((strchr(he->h_name, '.'))!=NULL && (strchr(hname, '.'))==NULL) {
549 					strncpy(fqdn, he->h_name, FQDN_SIZE);
550 				}
551 				else {
552 					strncpy(fqdn, hname, FQDN_SIZE);
553 				}
554 			}
555 		}
556 		else {
557 			fprintf(stderr, "error: cannot resolve local hostname: %s\n", hname);
558 			exit_code(2);
559 		}
560 	}
561 	if ((strchr(fqdn, '.'))==NULL) {
562 		if (hostname) {
563 			fprintf(stderr, "warning: %s is not resolvable... continouing anyway\n", fqdn);
564 			strncpy(fqdn, hostname, FQDN_SIZE);
565 		}
566 		else {
567 			fprintf(stderr, "error: this FQDN or IP is not valid: %s\n", fqdn);
568 			exit_code(2);
569 		}
570 	}
571 
572 	if (verbose > 2)
573 		printf("fqdnhostname: %s\n", fqdn);
574 }
575 
576 /* this function searches for search in mess and replaces it with
577    replacement */
replace_string(char * mess,char * search,char * replacement)578 void replace_string(char *mess, char *search, char *replacement){
579 	char *backup, *insert;
580 
581 	insert=STRCASESTR(mess, search);
582 	if (insert==NULL){
583 		if (verbose > 2)
584 			fprintf(stderr, "warning: could not find this '%s' replacement string in "
585 					"message\n", search);
586 	}
587 	else {
588 		while (insert){
589 			backup=str_alloc(strlen(insert)+1);
590 			strcpy(backup, insert+strlen(search));
591 			strcpy(insert, replacement);
592 			strcpy(insert+strlen(replacement), backup);
593 			free(backup);
594 			insert=STRCASESTR(mess, search);
595 		}
596 	}
597 }
598 
599 /* checks if the strings contains special double marks and then
600  * replace all occurences of this strings in the message */
replace_strings(char * mes,char * strings)601 void replace_strings(char *mes, char *strings) {
602 	char *pos, *atr, *val, *repl, *end;
603 	char sep;
604 
605 	pos=atr=val=repl = NULL;
606 #ifdef DEBUG
607 	printf("replace_strings entered\nstrings: '%s'\n", strings);
608 #endif
609 	if ((isalnum(*strings) != 0) &&
610 		(isalnum(*(strings + strlen(strings) - 1)) != 0)) {
611 		replace_string(req, "$replace$", replace_str);
612 	}
613 	else {
614 		sep = *strings;
615 #ifdef DEBUG
616 		printf("sep: '%c'\n", sep);
617 #endif
618 		end = strings + strlen(strings);
619 		pos = strings + 1;
620 		while (pos < end) {
621 			atr = pos;
622 			pos = strchr(atr, sep);
623 			if (pos != NULL) {
624 				*pos = '\0';
625 				val = pos + 1;
626 				pos = strchr(val, sep);
627 				if (pos != NULL) {
628 					*pos = '\0';
629 					pos++;
630 				}
631 			}
632 #ifdef DEBUG
633 			printf("atr: '%s'\nval: '%s'\n", atr, val);
634 #endif
635 			if ((atr != NULL) && (val != NULL)) {
636 				repl = str_alloc(strlen(val) + 3);
637 				if (repl == NULL) {
638 					printf("failed to allocate memory\n");
639 					exit_code(2);
640 				}
641 				sprintf(repl, "$%s$", atr);
642 				replace_string(mes, repl, val);
643 				free(repl);
644 			}
645 #ifdef DEBUG
646 			printf("pos: '%s'\n", pos);
647 #endif
648 		}
649 	}
650 #ifdef DEBUG
651 	printf("mes:\n'%s'\n", mes);
652 #endif
653 }
654 
655 /* insert \r in front of all \n if it is not present allready */
insert_cr(char * mes)656 void insert_cr(char *mes){
657 	char *lf, *pos, *backup;
658 
659 	pos = mes;
660 	lf = strchr(pos, '\n');
661 	while ((lf != NULL) && (*(--lf) != '\r')) {
662 		backup=str_alloc(strlen(lf)+2);
663 		strcpy(backup, lf+1);
664 		*(lf+1) = '\r';
665 		strcpy(lf+2, backup);
666 		free(backup);
667 		pos = lf+3;
668 		lf = strchr(pos, '\n');
669 	}
670 	lf = STRCASESTR(mes, "\r\n\r\n");
671 	if (lf == NULL) {
672 		lf = mes + strlen(mes);
673 		sprintf(lf, "\r\n");
674 	}
675 }
676 
677 /* sipmly swappes the content of the two buffers */
swap_buffers(char * fst,char * snd)678 void swap_buffers(char *fst, char *snd) {
679 	char *tmp;
680 
681 	if (fst == snd)
682 		return;
683 	tmp = str_alloc(strlen(fst)+1);
684 	strcpy(tmp, fst);
685 	strcpy(fst, snd);
686 	strcpy(snd, tmp);
687 	free(tmp);
688 }
689 
swap_ptr(char ** fst,char ** snd)690 void swap_ptr(char **fst, char **snd)
691 {
692 	char *tmp;
693 
694 	tmp = *fst;
695 	*fst = *snd;
696 	*snd = tmp;
697 }
698 
699 /* trashes one character in buff randomly */
trash_random(char * message)700 void trash_random(char *message)
701 {
702 	int r;
703 	float t;
704 	char *position;
705 
706 	t=(float)rand()/RAND_MAX;
707 	r=(int)(t * (float)strlen(message));
708 	position=message+r;
709 	r=(int)(t*(float)255);
710 	*position=(char)r;
711 	if (verbose > 2)
712 		printf("request:\n%s\n", message);
713 }
714 
715 /* this function is taken from traceroute-1.4_p12
716    which is distributed under the GPL and it returns
717    the difference between to timeval structs */
deltaT(struct timeval * t1p,struct timeval * t2p)718 double deltaT(struct timeval *t1p, struct timeval *t2p)
719 {
720 	register double dt;
721 
722 	dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
723 			(double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
724 	return (dt);
725 }
726 
727 /* returns one if the string contains only numbers otherwise zero */
is_number(char * number)728 int is_number(char *number)
729 {
730 	int digit = 1;
731 	while (digit && (*number != '\0')) {
732 		digit = isdigit(*number);
733 		number++;
734 	}
735 	return digit;
736 }
737 
738 /* tries to convert the given string into an integer. it strips
739  * white-spaces and exits if an error happens */
str_to_int(char * num)740 int str_to_int(char *num)
741 {
742 	int ret;
743 
744 #ifdef HAVE_STRTOL
745 	errno = 0;
746 	ret = strtol(num, NULL, 10);
747 	if (errno == EINVAL || errno == ERANGE) {
748 		printf("%s\n", num);
749 		perror("integer converting error");
750 		exit_code(2);
751 	}
752 #else
753 	char backup;
754 	int len = strlen(num);
755 	char *start = num;
756 	char *end = num + len;
757 
758 	while (!isdigit(*start) && isspace(*start) && start < end)
759 		start++;
760 	end = start;
761 	end++;
762 	while (end < num + len && *end != '\0' && !isspace(*end))
763 		end++;
764 	backup = *end;
765 	*end = '\0';
766 	if (!is_number(start)) {
767 		fprintf(stderr, "error: string is not a number: %s\n", start);
768 		exit_code(2);
769 	}
770 	ret = atoi(start);
771 	*end = backup;
772 	if (ret <= 0) {
773 		fprintf(stderr, "error: failed to convert string to integer: %s\n", num);
774 		exit_code(2);
775 	}
776 #endif
777 	return ret;
778 }
779 
780 /* reads into the given buffer from standard input until the EOF
781  * character, LF character or the given size of the buffer is exceeded */
read_stdin(char * buf,int size,int ret)782 int read_stdin(char *buf, int size, int ret)
783 {
784 	int i, j;
785 
786 	for(i = 0; i < size - 1; i++) {
787 		j = getchar();
788 		if (((ret == 0) && (j == EOF)) ||
789 			((ret == 1) && (j == '\n'))) {
790 			*(buf + i) = '\0';
791 			return i;
792 		}
793 		else {
794 			*(buf + i) = j;
795 		}
796 	}
797 	*(buf + i) = '\0';
798 	if (verbose)
799 		fprintf(stderr, "warning: readin buffer size exceeded\n");
800 	return i;
801 }
802 
803 /* tries to allocate the given size of memory and sets it all to zero.
804  * if the allocation fails it exits */
str_alloc(size_t size)805 void *str_alloc(size_t size)
806 {
807 	char *ptr;
808 #ifdef HAVE_CALLOC
809 	ptr = calloc(1, size);
810 #else
811 	ptr = malloc(size);
812 #endif
813 	if (ptr == NULL) {
814 		fprintf(stderr, "error: memory allocation failed\n");
815 		exit_code(255);
816 	}
817 #ifndef HAVE_CALLOC
818 	memset(ptr, 0, size);
819 #endif
820 	return ptr;
821 }
822