diff -Nru sipsak-0.9.6+git20170713/auth.c sipsak-0.9.7/auth.c --- sipsak-0.9.6+git20170713/auth.c 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/auth.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,402 +0,0 @@ -/* - * Copyright (C) 2002-2004 Fhg Fokus - * Copyright (C) 2004-2005 Nils Ohlmeier - * - * This file belongs to sipsak, a free sip testing tool. - * - * sipsak is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * sipsak is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#include "sipsak.h" -#include "auth.h" -#include "exit_code.h" -#include "helper.h" -#include "md5.h" - -#ifdef HAVE_OPENSSL_SHA1 -# include -#endif - -#define SIPSAK_ALGO_MD5 1 -#define SIPSAK_ALGO_SHA1 2 -#define SIPSAK_ALGO_SHA256 3 - -/* converts a hash into hex output - taken from the RFC 2617 */ -void cvt_hex(unsigned char *_b, unsigned char *_h, int length) -{ - unsigned short i; - unsigned char j; - - for (i = 0; i < length; i++) { - j = (_b[i] >> 4) & 0xf; - if (j <= (unsigned char)9) { - _h[i * 2] = (j + (unsigned char)'0'); - } else { - _h[i * 2] = (unsigned char)(j + (unsigned char)'a' - (unsigned char)10); - } - j = _b[i] & 0xf; - if (j <= (unsigned char)9) { - _h[i * 2 + 1] = (j + (unsigned char)'0'); - } else { - _h[i * 2 + 1] = (unsigned char)(j + (unsigned char)'a' - (unsigned char)10); - } - }; - _h[2*length] = '\0'; -} - -/* check for, create and insert a auth header into the message */ -void insert_auth(char *message, char *authreq) -{ - char *auth, *begin, *end, *insert, *backup, *realm, *usern, *nonce; - char *method, *uri; - char *qop_tmp = NULL; - unsigned char ha1[SIPSAK_HASHLEN], ha2[SIPSAK_HASHLEN], resp[SIPSAK_HASHLEN]; - unsigned char ha1_hex[SIPSAK_HASHHEXLEN+1], ha2_hex[SIPSAK_HASHHEXLEN+1], resp_hex[SIPSAK_HASHHEXLEN+1]; - int qop_auth=0, proxy_auth=0, algo=0; - unsigned int cnonce; - MD5_CTX Md5Ctx; -#ifdef HAVE_OPENSSL_SHA1 - SHA_CTX Sha1Ctx; - SHA256_CTX Sha256Ctx; -#endif - - auth=begin=end=insert=backup=realm=usern=nonce=method=uri = NULL; - - memset(&ha1[0], '\0', SIPSAK_HASHLEN); - memset(&ha2[0], '\0', SIPSAK_HASHLEN); - memset(&resp[0], '\0', SIPSAK_HASHLEN); - memset(&ha1_hex[0], '\0', SIPSAK_HASHHEXLEN+1); - memset(&ha2_hex[0], '\0', SIPSAK_HASHHEXLEN+1); - memset(&resp_hex[0], '\0', SIPSAK_HASHHEXLEN+1); - - /* prevent double auth insertion */ - if ((begin=STRCASESTR(message, AUTH_STR))!=NULL || - (begin=STRCASESTR(message, PROXYAUZ_STR))!=NULL) { - fprintf(stderr, "request:\n%s\nresponse:\n%s\nerror: authorization failed\n " - " request already contains (Proxy-) Authorization, but " - "received 40[1|7], see above\n", message, authreq); - exit_code(2, __PRETTY_FUNCTION__, "failed to add auth header, because request contained already one"); - } - /* make a backup of all except the request line because for - simplicity we insert the auth header direct behind the request line */ - insert=strchr(message, '\n'); - if (!insert) { - printf("failed to find newline\n"); - return; - } - insert++; - backup=str_alloc(strlen(insert)+1); - strncpy(backup, insert, strlen(insert)); - - begin=STRCASESTR(authreq, WWWAUTH_STR); - if (begin==NULL) { - begin=STRCASESTR(authreq, PROXYAUTH_STR); - proxy_auth = 1; - } - if (begin) { - /* make a copy of the auth header to prevent that our searches - hit content of other header fields */ - end=strchr(begin, '\n'); - auth=str_alloc((size_t)(end-begin+1)); - strncpy(auth, begin, (size_t)(end-begin)); - /* we support Digest with MD5 or SHA1 */ - if ((begin=STRCASESTR(auth, "Basic"))!=NULL) { - fprintf(stderr, "%s\nerror: authentication method Basic is deprecated since" - " RFC 3261 and not supported by sipsak\n", authreq); - exit_code(3, __PRETTY_FUNCTION__, "authentication method 'Basic' is deprecated"); - } - if ((begin=STRCASESTR(auth, "Digest"))==NULL) { - fprintf(stderr, "%s\nerror: couldn't find authentication method Digest in " - "the 40[1|7] response above\n", authreq); - exit_code(3, __PRETTY_FUNCTION__, "missing authentication method 'Digest' in reply"); - } - if ((begin=STRCASESTR(auth, "algorithm="))!=NULL) { - begin+=10; - if ((STRNCASECMP(begin, "MD5", 3))==0 || (STRNCASECMP(begin, "\"MD5\"", 5))==0) { - algo = SIPSAK_ALGO_MD5; - } -#ifdef HAVE_OPENSSL_SHA1 - else if ((STRNCASECMP(begin, "SHA1", 4))==0 || (STRNCASECMP(begin, "\"SHA1\"", 6))==0) { - algo = SIPSAK_ALGO_SHA1; - } - else if ((STRNCASECMP(begin, "SHA-256", 7))==0 || (STRNCASECMP(begin, "\"SHA-256\"", 9))==0) { - algo = SIPSAK_ALGO_SHA256; - } -#endif - else { - fprintf(stderr, "\n%s\nerror: unsupported authentication algorithm\n", authreq); - exit_code(2, __PRETTY_FUNCTION__, "unsupported authentication algorithm"); - } - } - else { - algo = SIPSAK_ALGO_MD5; - } - /* we need the username at some points */ - if (auth_username != NULL) { - usern = auth_username; - } - else { - usern=str_alloc(strlen(username)+11); - if (nameend>0) - snprintf(usern, strlen(username)+10, "%s%i", username, namebeg); - else - snprintf(usern, strlen(username)+10, "%s", username); - } - /* extract the method from the original request */ - end=strchr(message, ' '); - method=str_alloc((size_t)(end-message+1)); - strncpy(method, message, (size_t)(end-message)); - /* extract the uri also */ - begin=end++; - begin++; - end=strchr(end, ' '); - uri=str_alloc((size_t)(end-begin+1)); - strncpy(uri, begin, (size_t)(end-begin)); - - /* lets start with some basic stuff... username, uri and algorithm */ - if (proxy_auth == 1) { - snprintf(insert, PROXYAUZ_STR_LEN+1, PROXYAUZ_STR); - insert+=PROXYAUZ_STR_LEN; - } - else { - snprintf(insert, AUTH_STR_LEN+1, AUTH_STR); - insert+=AUTH_STR_LEN; - } - snprintf(insert, strlen(usern)+14, "username=\"%s\", ", usern); - insert+=strlen(insert); - snprintf(insert, strlen(uri)+9, "uri=\"%s\", ", uri); - insert+=strlen(insert); - snprintf(insert, ALGO_STR_LEN+1, ALGO_STR); - insert+=ALGO_STR_LEN; - if (algo == SIPSAK_ALGO_MD5) { - snprintf(insert, MD5_STR_LEN+1, MD5_STR); - insert+=MD5_STR_LEN; - } -#ifdef HAVE_OPENSSL_SHA1 - else if (algo == SIPSAK_ALGO_SHA1) { - snprintf(insert, SHA1_STR_LEN+1, SHA1_STR); - insert+=SHA1_STR_LEN; - } - else if (algo == SIPSAK_ALGO_SHA256) { - snprintf(insert, SHA256_STR_LEN+1, SHA256_STR); - insert+=SHA256_STR_LEN; - } -#endif - /* search for the realm, copy it to request and extract it for hash*/ - if ((begin=STRCASESTR(auth, REALM_STR))!=NULL) { - end=strchr(begin, ','); - if (!end) - end=strchr(begin, '\r'); - strncpy(insert, begin, (size_t)(end-begin+1)); - insert=insert+(end-begin+1); - if (*(insert-1) == '\r') - *(insert-1)=','; - snprintf(insert, 2, " "); - insert++; - begin+=REALM_STR_LEN+1; - end--; - realm=str_alloc((size_t)(end-begin+1)); - strncpy(realm, begin, (size_t)(end-begin)); - } - else { - fprintf(stderr, "%s\nerror: realm not found in 401 above\n", authreq); - exit_code(3, __PRETTY_FUNCTION__, "realm not found in reply"); - } - /* copy opaque if needed */ - if ((begin=STRCASESTR(auth, OPAQUE_STR))!=NULL) { - end=strchr(begin, ','); - if (!end) { - end=strchr(begin, '\r'); - } - strncpy(insert, begin, (size_t)(end-begin+1)); - insert=insert+(end-begin+1); - if (*(insert-1) == '\r') - *(insert-1)=','; - snprintf(insert, 2, " "); - insert++; - } - /* lets see if qop=auth is uspported */ - if ((begin=STRCASESTR(auth, QOP_STR))!=NULL) { - if (STRCASESTR(begin, QOPAUTH_STR)==NULL) { - fprintf(stderr, "response\n%s\nerror: qop \"auth\" not supported by" - " server\n", authreq); - exit_code(3, __PRETTY_FUNCTION__, "qop 'auth' is not supported by server"); - } - qop_auth=1; - } - /* search, copy and extract the nonce */ - if ((begin=STRCASESTR(auth, NONCE_STR))!=NULL) { - end=strchr(begin, ','); - if (!end) - end=strchr(begin, '\r'); - strncpy(insert, begin, (size_t)(end-begin+1)); - insert=insert+(end-begin+1); - if (*(insert-1) == '\r') - *(insert-1)=','; - snprintf(insert, 2, " "); - insert++; - begin+=NONCE_STR_LEN+1; - end--; - nonce=str_alloc((size_t)(end-begin+1)); - strncpy(nonce, begin, (size_t)(end-begin)); - } - else { - fprintf(stderr, "%s\nerror: nonce not found in 401 above\n", authreq); - exit_code(3, __PRETTY_FUNCTION__, "missing nonce in reply"); - } - /* if qop is supported we need som additional header */ - if (qop_auth == 1) { - snprintf(insert, QOP_STR_LEN+QOPAUTH_STR_LEN+3, "%s%s, ", QOP_STR, QOPAUTH_STR); - insert+=strlen(insert); - nonce_count++; - snprintf(insert, NC_STR_LEN+11, "%s%08x, ", NC_STR, nonce_count); - insert+=strlen(insert); - cnonce=(unsigned int)rand(); - snprintf(insert, 12+8, "cnonce=\"%x\", ", cnonce); - insert+=strlen(insert); - /* hopefully 100 is enough */ - qop_tmp=str_alloc(100); - snprintf(qop_tmp, 8+8+8, "%08x:%x:auth:", nonce_count, cnonce); - } - /* if no password is given we try it with empty password */ - if (!password) - password = EMPTY_STR; - - if (algo == SIPSAK_ALGO_MD5) { - if (authhash) { - strncpy((char*)&ha1_hex[0], authhash, SIPSAK_HASHHEXLEN_MD5); - } - else { - MD5Init(&Md5Ctx); - MD5Update(&Md5Ctx, usern, (unsigned int)strlen(usern)); - MD5Update(&Md5Ctx, ":", 1); - MD5Update(&Md5Ctx, realm, (unsigned int)strlen(realm)); - MD5Update(&Md5Ctx, ":", 1); - MD5Update(&Md5Ctx, password, (unsigned int)strlen(password)); - MD5Final(&ha1[0], &Md5Ctx); - cvt_hex(&ha1[0], &ha1_hex[0], SIPSAK_HASHLEN_MD5); - } - - MD5Init(&Md5Ctx); - MD5Update(&Md5Ctx, method, (unsigned int)strlen(method)); - MD5Update(&Md5Ctx, ":", 1); - MD5Update(&Md5Ctx, uri, (unsigned int)strlen(uri)); - MD5Final(&ha2[0], &Md5Ctx); - cvt_hex(&ha2[0], &ha2_hex[0], SIPSAK_HASHLEN_MD5); - - MD5Init(&Md5Ctx); - MD5Update(&Md5Ctx, &ha1_hex, SIPSAK_HASHHEXLEN_MD5); - MD5Update(&Md5Ctx, ":", 1); - MD5Update(&Md5Ctx, nonce, (unsigned int)strlen(nonce)); - MD5Update(&Md5Ctx, ":", 1); - if (qop_auth == 1) { - MD5Update(&Md5Ctx, qop_tmp, (unsigned int)strlen(qop_tmp)); - } - MD5Update(&Md5Ctx, &ha2_hex, SIPSAK_HASHHEXLEN_MD5); - MD5Final(&resp[0], &Md5Ctx); - cvt_hex(&resp[0], &resp_hex[0], SIPSAK_HASHLEN_MD5); - } -#ifdef HAVE_OPENSSL_SHA1 - else if (algo == SIPSAK_ALGO_SHA1) { - if (authhash) { - strncpy((char*)&ha1_hex[0], authhash, SIPSAK_HASHHEXLEN_SHA1); - } - else { - SHA1_Init(&Sha1Ctx); - SHA1_Update(&Sha1Ctx, usern, (unsigned int)strlen(usern)); - SHA1_Update(&Sha1Ctx, ":", 1); - SHA1_Update(&Sha1Ctx, realm, (unsigned int)strlen(realm)); - SHA1_Update(&Sha1Ctx, ":", 1); - SHA1_Update(&Sha1Ctx, password, (unsigned int)strlen(password)); - SHA1_Final(&ha1[0], &Sha1Ctx); - cvt_hex(&ha1[0], &ha1_hex[0], SIPSAK_HASHLEN_SHA1); - } - - SHA1_Init(&Sha1Ctx); - SHA1_Update(&Sha1Ctx, method, (unsigned int)strlen(method)); - SHA1_Update(&Sha1Ctx, ":", 1); - SHA1_Update(&Sha1Ctx, uri, (unsigned int)strlen(uri)); - SHA1_Final(&ha2[0], &Sha1Ctx); - cvt_hex(&ha2[0], &ha2_hex[0], SIPSAK_HASHLEN_SHA1); - - SHA1_Init(&Sha1Ctx); - SHA1_Update(&Sha1Ctx, &ha1_hex, SIPSAK_HASHHEXLEN_SHA1); - SHA1_Update(&Sha1Ctx, ":", 1); - SHA1_Update(&Sha1Ctx, nonce, (unsigned int)strlen(nonce)); - SHA1_Update(&Sha1Ctx, ":", 1); - if (qop_auth == 1) { - SHA1_Update(&Sha1Ctx, qop_tmp, (unsigned int)strlen(qop_tmp)); - } - SHA1_Update(&Sha1Ctx, &ha2_hex, SIPSAK_HASHHEXLEN_SHA1); - SHA1_Final(&resp[0], &Sha1Ctx); - cvt_hex(&resp[0], &resp_hex[0], SIPSAK_HASHLEN_SHA1); - } - else if (algo == SIPSAK_ALGO_SHA256) { - if (authhash) { - strncpy((char*)&ha1_hex[0], authhash, SIPSAK_HASHHEXLEN_SHA256); - } - else { - SHA256_Init(&Sha256Ctx); - SHA256_Update(&Sha256Ctx, usern, (unsigned int)strlen(usern)); - SHA256_Update(&Sha256Ctx, ":", 1); - SHA256_Update(&Sha256Ctx, realm, (unsigned int)strlen(realm)); - SHA256_Update(&Sha256Ctx, ":", 1); - SHA256_Update(&Sha256Ctx, password, (unsigned int)strlen(password)); - SHA256_Final(&ha1[0], &Sha256Ctx); - cvt_hex(&ha1[0], &ha1_hex[0], SIPSAK_HASHLEN_SHA256); - } - - SHA256_Init(&Sha256Ctx); - SHA256_Update(&Sha256Ctx, method, (unsigned int)strlen(method)); - SHA256_Update(&Sha256Ctx, ":", 1); - SHA256_Update(&Sha256Ctx, uri, (unsigned int)strlen(uri)); - SHA256_Final(&ha2[0], &Sha256Ctx); - cvt_hex(&ha2[0], &ha2_hex[0], SIPSAK_HASHLEN_SHA256); - - SHA256_Init(&Sha256Ctx); - SHA256_Update(&Sha256Ctx, &ha1_hex, SIPSAK_HASHHEXLEN_SHA256); - SHA256_Update(&Sha256Ctx, ":", 1); - SHA256_Update(&Sha256Ctx, nonce, (unsigned int)strlen(nonce)); - SHA256_Update(&Sha256Ctx, ":", 1); - if (qop_auth == 1) { - SHA256_Update(&Sha256Ctx, qop_tmp, (unsigned int)strlen(qop_tmp)); - } - SHA256_Update(&Sha256Ctx, &ha2_hex, SIPSAK_HASHHEXLEN_SHA256); - SHA256_Final(&resp[0], &Sha256Ctx); - cvt_hex(&resp[0], &resp_hex[0], SIPSAK_HASHLEN_SHA256); - } -#endif - - snprintf(insert, RESPONSE_STR_LEN+1, RESPONSE_STR); - insert+=RESPONSE_STR_LEN; - snprintf(insert, sizeof(resp_hex) + 8,"\"%s\"\r\n", &resp_hex[0]); - insert+=strlen(insert); - /* the auth header is complete, reinsert the rest of the request */ - strncpy(insert, backup, strlen(backup)); - } - else { - fprintf(stderr, "%s\nerror: couldn't find Proxy- or WWW-Authentication header" - " in the 401 response above\n", authreq); - exit_code(3, __PRETTY_FUNCTION__, "missing authentication header in reply"); - } - if (verbose>1) - printf("authorizing\n"); - /* hopefully we free all here */ - free(backup); - free(auth); - free(method); - free(uri); - free(realm); - free(nonce); - if (auth_username == NULL) free(usern); - if (qop_auth == 1) free(qop_tmp); -} - diff -Nru sipsak-0.9.6+git20170713/auth.h sipsak-0.9.7/auth.h --- sipsak-0.9.6+git20170713/auth.h 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/auth.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2002-2004 Fhg Fokus - * Copyright (C) 2004-2005 Nils Ohlmeier - * - * This file belongs to sipsak, a free sip testing tool. - * - * sipsak is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * sipsak is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef SIPSAK_AUTH_H -#define SIPSAK_AUTH_H - -void insert_auth(char *message, char *authreq); - -#endif diff -Nru sipsak-0.9.6+git20170713/ChangeLog sipsak-0.9.7/ChangeLog --- sipsak-0.9.6+git20170713/ChangeLog 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/ChangeLog 2019-04-27 04:54:34.000000000 +0000 @@ -1,3 +1,19 @@ +* version 0.9.7 + - added new option -E which overrules SRV result + - added new option -J to take ha1 instead of password + - dont retransmit on reliable transports + - added --disable-ips configure option which allows to compile the oldstyle --numeric behavior + - added new option -k only available with TLS support + - added 'star' as special word for the contact option -C + - fixed overwritting of outbound proxy if domainname is an IP; thanks to Alexander Litvak + - added option -Z to modify SIP_T1 at run time + - added syslog support + - enabled -c parameter for Inivte mode + - added new options for TLS (ca-cert, client-cert, ignore-cert-failure) + Note: these options are only available as long options + - added option to ignore TLS certificate verification errors + - added option -k, --local-ip + - added SHA-256 as a possible algorithm for digest authentication * version 0.9.6 - added new option -j to add a header - added support for multiple variable replacement (option -g) diff -Nru sipsak-0.9.6+git20170713/configure.ac sipsak-0.9.7/configure.ac --- sipsak-0.9.6+git20170713/configure.ac 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/configure.ac 2019-04-27 04:54:34.000000000 +0000 @@ -2,10 +2,10 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.59) -AC_INIT([sipsak],[0.9.7pre],[nils@sipsak.org]) +AC_INIT([sipsak],[0.9.7],[nils@sipsak.org]) AM_INIT_AUTOMAKE([subdir-objects]) AM_MAINTAINER_MODE -AC_CONFIG_SRCDIR([sipsak.c]) +AC_CONFIG_SRCDIR([src/sipsak.c]) AC_CONFIG_HEADER([config.h]) # Checks for programs. @@ -52,14 +52,16 @@ AC_CHECK_FUNCS([getchar gethostbyname gethostname getopt getpid gettimeofday memset ntohs regcomp select socket strchr strcmp strstr strtol uname],,[AC_MSG_ERROR([missing required function (see above)])]) AC_CHECK_FUNCS([calloc getdomainname getopt_long inet_ntop strncasecmp strcasestr syslog]) +PKG_PROG_PKG_CONFIG + # Check if the check unit test framework is available PKG_CHECK_MODULES([CHECK], [check >= 0.9.3], [ AC_DEFINE([HAVE_CHECK_H], [1], [Has check.h]) - ], [] -) + ],:) PKG_CHECK_MODULES([GNUTLS], [gnutls >= 1.0.0], [ AC_DEFINE([HAVE_GNUTLS], [1], [Has gnutls >= 1.0.0]) + HAVE_GNUTLS=1 LIBS="${LIBS} ${GNUTLS_LIBS}" CFLAGS="${CFLAGS} ${GNUTLS_CFLAGS}" ], [ @@ -77,8 +79,19 @@ ]) PKG_CHECK_MODULES([GNUTLS319], [gnutls >= 3.1.9], [ AC_DEFINE([HAVE_GNUTLS_319], [1], [Has gntuls >= 3.1.9]) - ], [] -) + ],:) + +dnl --- +dnl Check if GnuTLS has SRP support. +dnl --- +if test "$HAVE_GNUTLS" = "1"; then + AC_CHECK_LIB(gnutls, gnutls_srp_verifier, + [ + AC_DEFINE(HAVE_GNUTLS_SRP, 1, [if you have the function gnutls_srp_verifier]) + AC_SUBST(HAVE_GNUTLS_SRP, [1]) + ]) +fi + PKG_CHECK_MODULES([CARES], [libcares], [ AC_DEFINE([HAVE_CARES_H], [1], [Has cares.h]) @@ -101,6 +114,5 @@ SIPSAK_TLS SIPSAK_DBG_PRINT -AC_CONFIG_FILES([Makefile - tests/Makefile]) +AC_CONFIG_FILES([Makefile]) AC_OUTPUT diff -Nru sipsak-0.9.6+git20170713/debian/changelog sipsak-0.9.7/debian/changelog --- sipsak-0.9.6+git20170713/debian/changelog 2017-07-13 14:53:51.000000000 +0000 +++ sipsak-0.9.7/debian/changelog 2019-05-21 11:38:55.000000000 +0000 @@ -1,3 +1,13 @@ +sipsak (0.9.7-1) unstable; urgency=medium + + * New upstream version 0.9.7 + * update VCS-* migrated to salsa + * update debian/copyright path for md5.* files + * fix debian/watch file + * update standards version to 4.3.0, no changes needed + + -- Victor Seva Tue, 21 May 2019 13:38:55 +0200 + sipsak (0.9.6+git20170713-1) unstable; urgency=medium * New upstream version 0.9.6+git20170314 (Closes: #868096) diff -Nru sipsak-0.9.6+git20170713/debian/control sipsak-0.9.7/debian/control --- sipsak-0.9.6+git20170713/debian/control 2017-07-13 14:53:51.000000000 +0000 +++ sipsak-0.9.7/debian/control 2019-05-21 11:38:55.000000000 +0000 @@ -10,10 +10,10 @@ libgnutls-openssl-dev, libruli4-dev, pkg-config, -Standards-Version: 4.0.0 +Standards-Version: 4.3.0 Homepage: https://github.com/nils-ohlmeier/sipsak -Vcs-Browser: https://anonscm.debian.org/cgit/pkg-voip/sipsak.git -Vcs-Git: https://anonscm.debian.org/git/pkg-voip/sipsak.git +Vcs-Browser: https://salsa.debian.org/pkg-voip-team/sipsak +Vcs-Git: https://salsa.debian.org/pkg-voip-team/sipsak.git Package: sipsak Architecture: any diff -Nru sipsak-0.9.6+git20170713/debian/copyright sipsak-0.9.7/debian/copyright --- sipsak-0.9.6+git20170713/debian/copyright 2017-07-13 14:53:51.000000000 +0000 +++ sipsak-0.9.7/debian/copyright 2019-05-21 11:38:55.000000000 +0000 @@ -19,7 +19,7 @@ can be found in ‘/usr/share/common-licenses/GPL-2’ or in the dpkg source as the file ‘COPYING’. -Files: md5.* +Files: src/md5.* Copyright: Copyright © 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved diff -Nru sipsak-0.9.6+git20170713/debian/watch sipsak-0.9.7/debian/watch --- sipsak-0.9.6+git20170713/debian/watch 2017-07-13 14:53:51.000000000 +0000 +++ sipsak-0.9.7/debian/watch 2019-05-21 11:38:55.000000000 +0000 @@ -1,4 +1,4 @@ version=4 -opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%-$1.tar.gz%" \ +opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%sipsak-$1.tar.gz%" \ https://github.com/nils-ohlmeier/sipsak/tags \ (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian uupdate diff -Nru sipsak-0.9.6+git20170713/exit_code.c sipsak-0.9.7/exit_code.c --- sipsak-0.9.6+git20170713/exit_code.c 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/exit_code.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2002-2004 Fhg Fokus - * Copyright (C) 2004-2005 Nils Ohlmeier - * - * This file belongs to sipsak, a free sip testing tool. - * - * sipsak is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * sipsak is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "sipsak.h" - -#if HAVE_CONFIG_H -# include "config.h" -#endif - -#ifdef HAVE_STDIO_H -# include -#endif -#ifdef HAVE_STDLIB_H -# include -#endif -#ifdef HAVE_SYSLOG_H -# include -#endif - -#include "exit_code.h" - -enum exit_modes exit_mode = EM_DEFAULT; - -void log_message(const char *message) { - if ((sysl > 3) && (message != NULL)) { -#ifdef HAVE_SYSLOG - syslog(LOG_INFO, "%s", message); -#endif - } -} - -void exit_code(int code, const char *function, const char *reason) -{ -#ifdef WITH_TLS_TRANSP - if (transport == SIP_TLS_TRANSPORT) { -# ifdef USE_GNUTLS - if (tls_session) { - gnutls_deinit(tls_session); - } - if (xcred) { - gnutls_certificate_free_credentials(xcred); - } - gnutls_global_deinit(); -# else /* USE_GNUTLS */ -# ifdef USE_OPENSSL -# endif /* USE_OPENSSL */ -# endif /* USE_GNUTLS */ - } -#endif /* WITH_TLS_TRANSP */ - - if ((sysl > 0) && (reason != NULL)) { -#ifdef HAVE_SYSLOG - syslog(LOG_INFO, "%s: %s", function, reason); - closelog(); -#endif - } - - switch(exit_mode) { - case EM_DEFAULT: - if (code == 4) { - exit(0); - } else { - exit(code); - } - case EM_NAGIOS: - if (code == 0) { - printf("SIP ok\n"); - exit(0); - } else if (code == 4) { - printf("SIP warning\n"); - exit(1); - } else { - printf("SIP failure\n"); - exit(2); - } - default: - fprintf(stderr, "ERROR: unknown exit code\n"); - exit(1); - } -} diff -Nru sipsak-0.9.6+git20170713/exit_code.h sipsak-0.9.7/exit_code.h --- sipsak-0.9.6+git20170713/exit_code.h 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/exit_code.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2002-2004 Fhg Fokus - * Copyright (C) 2004-2005 Nils Ohlmeier - * - * This file belongs to sipsak, a free sip testing tool. - * - * sipsak is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * sipsak is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef SIPSAK_EXITCODE_H -#define SIPSAK_EXITCODE_H - -enum exit_modes { EM_DEFAULT, EM_NAGIOS }; - -extern enum exit_modes exit_mode; - -void log_message(const char *message); - -void exit_code(int code, const char *function, const char *reason); - -#endif diff -Nru sipsak-0.9.6+git20170713/header_f.c sipsak-0.9.7/header_f.c --- sipsak-0.9.6+git20170713/header_f.c 2017-07-13 14:47:05.000000000 +0000 +++ sipsak-0.9.7/header_f.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,628 +0,0 @@ -/* - * Copyright (C) 2002-2004 Fhg Fokus - * Copyright (C) 2004-2005 Nils Ohlmeier - * - * This file belongs to sipsak, a free sip testing tool. - * - * sipsak is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * sipsak is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "sipsak.h" - -#include "header_f.h" -#include "exit_code.h" -#include "helper.h" -#include "shoot.h" - - -/* add the given header(s) below the request line */ -void insert_header(char *mes, char *header, int first) { - char *ins, *backup; - - if (first) { - ins = strchr(mes, '\n'); - if (ins == NULL) { - printf("failed to find a new line in the message\n"); - exit_code(2, __PRETTY_FUNCTION__, "failed to find a new line in the message"); - } - ins++; - } - else { - ins = mes; - } - backup = str_alloc(strlen(ins) + 1); - strncpy(backup, ins, strlen(ins)); - strncpy(ins, header, strlen(header)); - strncpy(ins + strlen(header), backup, strlen(backup)+1); - free(backup); -} - -/* add a Via Header Field in the message. */ -void add_via(char *mes) -{ - char *via_line, *via, *backup; - - if ((via=STRCASESTR(mes, VIA_STR)) == NULL && - (via=STRCASESTR(mes, VIA_SHORT_STR)) == NULL) { - /* We didn't found a Via so we insert our via - direct after the first line. */ - via=strchr(mes,'\n'); - if(via == NULL) { - fprintf(stderr, "error: failed to find a position to insert Via:\n" - "'%s'\n", mes); - exit_code(2, __PRETTY_FUNCTION__, "failed to find position to insert to insert Via header"); - } - via++; - } - if (*via == '\n') - via++; - /* build our own Via-header-line */ - via_line = str_alloc(VIA_SIP_STR_LEN+TRANSPORT_STR_LEN+1+ - strlen(fqdn)+15+30+1); - snprintf(via_line, - VIA_SIP_STR_LEN+TRANSPORT_STR_LEN+1+strlen(fqdn)+15+30, - "%s%s %s:%i;branch=z9hG4bK.%08x;rport;alias\r\n", - VIA_SIP_STR, transport_str, fqdn, lport, rand()); - if (verbose > 2) - printf("our Via-Line: %s\n", via_line); - - if (strlen(mes)+strlen(via_line)>= BUFSIZE){ - printf("can't add our Via Header Line because file is too big\n"); - exit_code(2, __PRETTY_FUNCTION__, "Via header to big for buffer"); - } - /* finnaly make a backup, insert our via and append the backup */ - backup=str_alloc((strlen(via)+1)); - strncpy(backup, via, strlen(via)); - strncpy(via, via_line, strlen(via_line)); - strncpy(via+strlen(via_line), backup, strlen(backup)+1); - if (verbose > 2) - printf("New message with Via-Line:\n%s\n", mes); - free(via_line); - free(backup); -} - -/* copy the via lines from the message to the message - reply for correct routing of our reply. -*/ -void cpy_vias(char *reply, char *dest){ - char *first_via, *middle_via, *last_via, *backup; - - /* lets see if we find any via */ - if ((first_via=STRCASESTR(reply, VIA_STR))==NULL && - (first_via=STRCASESTR(reply, VIA_SHORT_STR))==NULL ){ - fprintf(stderr, "error: the received message doesn't contain a Via header\n"); - exit_code(3, __PRETTY_FUNCTION__, "missing Via header in message"); - } - last_via=first_via+4; - middle_via=last_via; - /* proceed additional via lines */ - while ((middle_via=STRCASESTR(last_via, VIA_STR))!=NULL || - (middle_via=STRCASESTR(last_via, VIA_SHORT_STR))!=NULL ) - last_via=middle_via+4; - last_via=strchr(last_via, '\n'); - middle_via=strchr(dest, '\n')+1; - /* make a backup, insert the vias after the first line and append - backup - */ - backup=str_alloc(strlen(middle_via)+1); - strcpy(backup, middle_via); - strncpy(middle_via, first_via, (size_t)(last_via-first_via+1)); - strcpy(middle_via+(last_via-first_via+1), backup); - free(backup); - if (verbose > 2) - printf("message reply with vias included:\n%s\n", dest); -} - -void cpy_to(char *reply, char *dest) { - char *src_to, *dst_to, *backup, *tmp; - - /* find the position where we want to insert the To */ - if ((dst_to=STRCASESTR(dest, TO_STR))==NULL && - (dst_to=STRCASESTR(dest, TO_SHORT_STR))==NULL) { - fprintf(stderr, "error: could not find To in the destination: %s\n", dest); - exit_code(2, __PRETTY_FUNCTION__, "missing To header in target buffer"); - } - if (*dst_to == '\n') - dst_to++; - /* find the To we want to copy */ - if ((src_to=STRCASESTR(reply, TO_STR))==NULL && - (src_to=STRCASESTR(reply, TO_SHORT_STR))==NULL) { - if (verbose > 0) - fprintf(stderr, "warning: could not find To in reply. " - "trying with original To\n"); - } - else { - if (*src_to == '\n') - src_to++; - /* both To found, so copy it */ - tmp=strchr(dst_to, '\n'); - tmp++; - backup=str_alloc(strlen(tmp)+1); - strcpy(backup, tmp); - tmp=strchr(src_to, '\n'); - strncpy(dst_to, src_to, (size_t)(tmp-src_to+1)); - strcpy(dst_to+(tmp-src_to+1), backup); - free(backup); - if (verbose >2) - printf("reply with copyed To:\n%s\n", dest); - } -} - -/* check for the existence of a Max-Forwards header field. if its - present it sets it to the given value, if not it will be inserted.*/ -void set_maxforw(char *mes, int value){ - char *max, *backup, *crlfi; - int maxforward; - - if ((max=STRCASESTR(mes, MAX_FRW_STR))==NULL){ - /* no max-forwards found so insert it after the first line*/ - max=strchr(mes,'\n'); - if (!max) { - printf("failed to find newline\n"); - exit_code(254, __PRETTY_FUNCTION__, "missing newline in buffer"); - } - max++; - backup=str_alloc(strlen(max)+1); - strncpy(backup, max, (size_t)(strlen(max))); - if (value == -1) { - maxforward = 70; // RFC3261 default - } - else { - maxforward = value; - } - snprintf(max, MAX_FRW_STR_LEN+6, "%s%i\r\n", MAX_FRW_STR, maxforward); - max=strchr(max,'\n'); - max++; - strncpy(max, backup, strlen(backup)+1); - free(backup); - if (verbose > 1) - printf("Max-Forwards %i inserted into header\n", maxforward); - if (verbose > 2) - printf("New message with inserted Max-Forwards:\n%s\n", mes); - } - else{ - /* found max-forwards => overwrite the value with maxforw*/ - crlfi=strchr(max,'\n'); - crlfi++; - backup=str_alloc(strlen(crlfi)+1); - strncpy(backup, crlfi, strlen(crlfi)); - crlfi=max + MAX_FRW_STR_LEN; - if (value == -1) { - maxforward = str_to_int(1, crlfi); - maxforward++; - } - else { - maxforward = value; - } - snprintf(crlfi, 6, "%i\r\n", maxforward); - crlfi=strchr(max,'\n'); - crlfi++; - strncpy(crlfi, backup, strlen(backup)+1); - free(backup); - if (verbose > 1) - printf("Max-Forwards set to %i\n", maxforward); - if (verbose > 2) - printf("New message with changed Max-Forwards:\n%s\n", mes); - } -} - -/* replaces the uri in first line of mes with the other uri */ -void uri_replace(char *mes, char *uri) -{ - char *foo, *backup; - - foo=strchr(mes, '\n'); - if (!foo) { - printf("failed to find newline\n"); - exit_code(254, __PRETTY_FUNCTION__, "missing newline in buffer"); - } - foo++; - backup=str_alloc(strlen(foo)+1); - strncpy(backup, foo, strlen(foo)); - foo=STRCASESTR(mes, "sip"); - strncpy(foo, uri, strlen(uri)); - strncpy(foo+strlen(uri), SIP20_STR, SIP20_STR_LEN); - strncpy(foo+strlen(uri)+SIP20_STR_LEN, backup, strlen(backup)+1); - free(backup); - if (verbose > 2) - printf("Message with modified uri:\n%s\n", mes); -} - -/* replace the Content-Length value with the given value */ -void set_cl(char* mes, int contentlen) { - char *cl, *cr, *backup; - - if ((cl=STRCASESTR(mes, CON_LEN_STR)) == NULL && - (cl=STRCASESTR(mes, CON_LEN_SHORT_STR)) == NULL) { - printf("missing Content-Length in message\n"); - return; - } - if (*cl == '\n') { - cl++; - } - cr = strchr(cl, '\n'); - cr++; - backup=str_alloc(strlen(cr)+1); - strncpy(backup, cr, strlen(cr)); - if (*cl == 'C') - cr=cl + CON_LEN_STR_LEN; - else - cr=cl + 3; - snprintf(cr, 6, "%i\r\n", contentlen); - cr=strchr(cr, '\n'); - cr++; - strncpy(cr, backup, strlen(backup)+1); - free(backup); - if (verbose > 2) { - printf("Content-Length set to %i\n" - "New message with changed Content-Length:\n%s\n", contentlen, mes); - } -} - -/* returns the content length from the message; in case of error it - * return -1 */ -int get_cl(char* mes) { - char *cl; - - if ((cl=STRCASESTR(mes, CON_LEN_STR)) == NULL && - (cl=STRCASESTR(mes, CON_LEN_SHORT_STR)) == NULL) { - if (verbose > 1) - printf("missing Content-Length in message\n"); - return -1; - } - if (*cl == '\n') { - cl+=3; - } - else { - cl+=15; - } - return str_to_int(1, cl); -} - -/* returns 1 if the rr_line contains the lr parameter - * otherwise 0 */ -int find_lr_parameter(char *rr_line) { - char *eol, *lr; - - eol = strchr(rr_line, '\n'); - lr = STRCASESTR(rr_line, ";lr"); - if ((eol == NULL) || (lr == NULL) || (lr > eol)) { - return 0; - } - else { - return 1; - } -} - -/* copies the Record-Route header from src to dst. - * if route is set Record-Route will be replaced by Route */ -void cpy_rr(char* src, char *dst, int route) { - char *rr, *cr, *cr2, *backup; - int len; - - cr = strchr(dst, '\n'); - if (cr == NULL) { - fprintf(stderr, "error: failed to find newline in destination\n"); - exit_code(3, __PRETTY_FUNCTION__, "missing newline in target buffer"); - } - cr++; - rr = STRCASESTR(src, RR_STR); - if (rr != NULL) { - if (find_lr_parameter(rr) == 0) { - fprintf(stderr, "error: strict routing is not support yet\n"); - exit_code(252, __PRETTY_FUNCTION__, "strict routing is not supported"); - } - backup=str_alloc(strlen(cr)+1); - strncpy(backup, cr, strlen(cr)); - if (route == 0) - len = RR_STR_LEN; - else - len = ROUTE_STR_LEN; - while (rr != NULL) { - if (route == 0) { - strncpy(cr, RR_STR, RR_STR_LEN); - } - else { - strncpy(cr, ROUTE_STR, ROUTE_STR_LEN); - } - cr += len; - cr2 = strchr(rr, '\n'); - if (cr2 == NULL) { - fprintf(stderr, "error: failed to find end of line\n"); - exit_code(3, __PRETTY_FUNCTION__, "missing newline in buffer"); - } - strncpy(cr, rr + RR_STR_LEN, (cr2 - (rr + len) + 1)); - cr+=(cr2 - (rr + RR_STR_LEN) + 1); - rr = STRCASESTR(++rr, RR_STR); - } - strncpy(cr, backup, strlen(backup)+1); - free(backup); - if (verbose > 2) - printf("New message with inserted Route:\n%s\n", dst); - } -} - -/* build an ACK from the given invite and reply. - * NOTE: space has to be allocated already for the ACK */ -void build_ack(char *invite, char *reply, char *dest, - struct sipsak_regexp *reg) { - char *tmp; - int len; - - if ((tmp = STRCASESTR(invite, "\r\n\r\n")) != NULL) { - len = (tmp + 4) - invite; - } - else { - len = strlen(invite); - } - memcpy(dest, invite, len); - *(dest + len) = '\0'; - replace_string(dest, "INVITE", "ACK"); - set_cl(dest, 0); - cpy_to(reply, dest); - if (regexec(&(reg->okexp), reply, 0, 0, 0)==0) { - cpy_rr(reply, dest, 1); - /* 200 ACK must be in new transaction */ - new_branch(dest); - if((tmp = uri_from_contact(reply))!= NULL) { - uri_replace(dest, tmp); - free(tmp); - } - } -} - -/* tryes to find the warning header filed and prints out the IP */ -void warning_extract(char *message) -{ - char *warning, *end, *mid, *server; - int srvsize; - - if ((warning=STRCASESTR(message, "Warning:"))==NULL) { - if (verbose > 0) - printf("'no Warning header found' "); - else - printf("?? "); - return; - } - end=strchr(warning, '"'); - end--; - warning=strchr(warning, '3'); - warning+=4; - mid=strchr(warning, ':'); - if (mid) - end=mid; - srvsize=end - warning + 1; - server=str_alloc((size_t)srvsize); - server=strncpy(server, warning, (size_t)(srvsize - 1)); - printf("%s ", server); - free(server); -} - -/* tries to find and return the number in the CSeq header */ -int cseq(char *message) -{ - char *cseq; - int num=-1; - - cseq=STRCASESTR(message, CSEQ_STR); - if (cseq) { - cseq+=6; - num=str_to_int(1, cseq); - if (num < 1) { - if (verbose > 2) - printf("CSeq found but not convertible\n"); - return 0; - } - return num; - } - if (verbose > 2) - printf("no CSeq found\n"); - return 0; -} - -/* if it find the Cseq number in the message it will increased by one */ -void increase_cseq(char *message, char *reply) -{ - int cs; - char *cs_s, *eol, *backup; - - cs = cseq(message); - if ((cs < 1) && (verbose > 1)) { - printf("CSeq increase failed because unable to extract CSeq number\n"); - return; - } - if (cs == INT_MAX) - cs = 1; - else - cs++; - cs_s=STRCASESTR(message, CSEQ_STR); - if (cs_s) { - cs_s+=6; - eol=strchr(cs_s, ' '); - eol++; - backup=str_alloc(strlen(eol)+1); - strncpy(backup, eol, (size_t)(strlen(eol))); - snprintf(cs_s, 11, "%i ", cs); - cs_s+=strlen(cs_s); - strncpy(cs_s, backup, strlen(backup)); - free(backup); - cseq_counter = cs; - } - else if (verbose > 1) - printf("'CSeq' not found in message\n"); - if (reply != NULL) { - cs_s=STRCASESTR(reply, CSEQ_STR); - if (cs_s) { - cs_s+=6; - eol=strchr(cs_s, ' '); - eol++; - backup=str_alloc(strlen(eol)+1); - strncpy(backup, eol, (size_t)(strlen(eol))); - snprintf(cs_s, 11, "%i ", cs); - cs_s+=strlen(cs_s); - strncpy(cs_s, backup, strlen(backup)); - free(backup); - } - else if (verbose > 1) - printf("'CSeq' not found in reply\n"); - } -} - -/* separates the given URI into the parts by setting the pointer but it - destroyes the URI */ -void parse_uri(char *uri, char **scheme, char **user, char **host, int *port) -{ - char *col, *col2, *at; - col = col2 = at = NULL; - *port = 0; - *scheme = *user = *host = NULL; - if ((col=strchr(uri,':'))!=NULL) { - if ((at=strchr(uri,'@'))!=NULL) { - *col = '\0'; - *at = '\0'; - if (at > col) { - *scheme = uri; - *user = ++col; - *host = ++at; - if ((col2=strchr(*host,':'))!=NULL) { - *col2 = '\0'; - *port = str_to_int(1, ++col2); - } - } - else { - *user = uri; - *host = ++at; - *port = str_to_int(1, ++col); - } - } - else { - *col = '\0'; - col++; - if ((col2=strchr(col,':'))!=NULL) { - *col2 = '\0'; - *scheme = uri; - *host = col; - *port = str_to_int(1, ++col2); - } - else { - if (is_number(col)) { - *host = uri; - *port = str_to_int(1, col); - } - else { - *scheme = uri; - *host = col; - } - } - } - } - else { - *host = uri; - } -} - -/* return a copy of the URI from the Contact of the message if found */ -char* uri_from_contact(char *message) -{ - char *contact, *end, *tmp, c; - - /* try to find the contact in the redirect */ - if ((contact=STRCASESTR(message, CONT_STR))==NULL && - (contact=STRCASESTR(message, CONT_SHORT_STR))==NULL ) { - if(verbose > 1) - printf("'Contact' not found in the message\n"); - return NULL; - } - if (*contact == '\n') - contact++; - - if((end=strchr(contact,'\r'))!=NULL) { - c = '\r'; - *end = '\0'; - } - else if((end=strchr(contact,'\n'))!=NULL) { - c = '\n'; - *end = '\0'; - } - else { - c = '\0'; - end = contact + strlen(contact); - } - - tmp = NULL; - - if ((contact=STRCASESTR(contact, "sip:"))!=NULL) { - if ((tmp=strchr(contact+4, ';'))!=NULL) { - *end = c; - end = tmp; - c = *end; - *end = '\0'; - } - if ((tmp=strchr(contact+4, '>'))!=NULL) { - *end = c; - end = tmp; - c = *end; - *end = '\0'; - } - tmp = str_alloc(strlen(contact)+1); - memcpy(tmp,contact,strlen(contact)); - } - - *end = c; - - return tmp; -} - -/* replace the 8 bytes behind the first magic cookie with a new - * random value */ -void new_branch(char *message) -{ - char *branch; - char backup; - - if((branch = STRCASESTR(message,"branch=z9hG4bK.")) != NULL) { - backup = *(branch+15+8); - snprintf(branch+15, 9, "%08x", rand()); - *(branch+15+8) = backup; - } -} - -/* increase the CSeq and insert a new branch value */ -void new_transaction(char *message, char *reply) -{ - increase_cseq(message, reply); - new_branch(message); -} - -/* just print the first line of the message */ -void print_message_line(char *message) -{ - char *crlf; - - crlf=strchr(message, '\n'); - if (!crlf) { - printf("failed to find newline\n"); - exit_code(254, __PRETTY_FUNCTION__, "missing newline in buffer"); - } - else if (*(crlf - 1) == '\r') - crlf--; - printf("%.*s\n", (int)(crlf - message), message); -} - -/* return pointer to the beginning of the message body */ -char* get_body(char *mes) { - char *cr; - - if ((cr = strstr(mes, "\r\n\r\n")) != NULL) { - cr+=4; - } - return cr; -} diff -Nru sipsak-0.9.6+git20170713/header_f.h sipsak-0.9.7/header_f.h --- sipsak-0.9.6+git20170713/header_f.h 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/header_f.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2002-2004 Fhg Fokus - * Copyright (C) 2004-2005 Nils Ohlmeier - * - * This file belongs to sipsak, a free sip testing tool. - * - * sipsak is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * sipsak is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef SIPSAK_HEADER_H -#define SIPSAK_HEADER_H - -#include "shoot.h" - -void insert_header(char *mes, char *header, int first); - -void add_via(char *mes); - -void cpy_vias(char *reply, char *dest); - -void cpy_to(char *reply, char *dest); - -void set_maxforw(char *mes, int value); - -void uri_replace(char *mes, char *uri); - -void set_cl(char* mes, int contentlen); - -int get_cl(char* mes); - -int find_lr_parameter(char *rr_line); - -void cpy_rr(char* src, char *dst, int route); - -void build_ack(char *invite, char *reply, char *dest, - struct sipsak_regexp *reg); - -void warning_extract(char *message); - -int cseq(char *message); - -void increase_cseq(char *message, char *reply); - -void parse_uri(char *uri, char **scheme, char **user, char **host, int *port); - -char* uri_from_contact(char *message); - -void new_branch(char *message); - -void new_transaction(char *message, char *reply); - -void print_message_line(char *message); - -char* get_body(char *mes); -#endif diff -Nru sipsak-0.9.6+git20170713/helper.c sipsak-0.9.7/helper.c --- sipsak-0.9.6+git20170713/helper.c 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/helper.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,851 +0,0 @@ -/* - * Copyright (C) 2002-2004 Fhg Fokus - * Copyright (C) 2004-2005 Nils Ohlmeier - * - * This file belongs to sipsak, a free sip testing tool. - * - * sipsak is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * sipsak is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#include "sipsak.h" - -#ifdef HAVE_STDARG_H -# include -#endif -#ifdef HAVE_NETDB_H -# include -#endif -#ifdef HAVE_UNISTD_H -# ifdef HAVE_SYS_TYPES_H -# include -# endif -# include -#endif -#ifdef HAVE_SYS_UTSNAME_H -# include -#endif -#ifdef HAVE_CTYPE_H -# include -#endif -#ifdef HAVE_ARPA_INET_H -# include -#endif -#ifdef HAVE_NETINET_IN_H -# include -#endif -#ifdef HAVE_RULI_H -# include -#endif -#ifdef HAVE_ERRNO_H -# include -#endif -#ifdef HAVE_CARES_H -# ifdef HAVE_ARPA_NAMESER_H -# include -# endif -# include -# ifndef NS_RRFIXEDSZ -# define NS_RRFIXEDSZ 10 -# define NS_QFIXEDSZ 4 -# define NS_HFIXEDSZ 12 -# endif - int caport; - unsigned long caadr; - char *ca_tmpname; - ares_channel channel; - -#endif // HAVE_CARES_H - -#include "helper.h" -#include "exit_code.h" - -/* returns 1 if the string an IP address otherwise zero */ -int is_ip(char *str) { - int i = 0; - int dotcount = 0; - - /*try understanding if this is a valid ip address - we are skipping the values of the octets specified here. - for instance, this code will allow 952.0.320.567 through*/ - while (*str != '\0') - { - for (i = 0; i < 3; i++, str++) - if (isdigit((int)*str) == 0) - break; - if (*str != '.') - break; - str++; - dotcount++; - } - - /* three dots with up to three digits in before, between and after ? */ - if (*str == '\0' && dotcount == 3 && i > 0 && i <= 3) - return 1; - else - return 0; -} - -/* take either a dot.decimal string of ip address or a -domain name and returns a NETWORK ordered long int containing -the address. i chose to internally represent the address as long for speedier -comparisons. - -any changes to getaddress have to be patched back to the net library. -contact: farhan@hotfoon.com - - returns zero if there is an error. - this is convenient as 0 means 'this' host and the traffic of - a badly behaving dns system remains inside (you send to 0.0.0.0) -*/ - -unsigned long getaddress(char *host) { - struct hostent* pent; - long addr; - - if (strlen(host) == 0) { - return 0; - } - if (is_ip(host)) { - return inet_addr(host); - } - - /* try the system's own resolution mechanism for dns lookup: - required only for domain names. - in spite of what the rfc2543 :D Using SRV DNS Records recommends, - we are leaving it to the operating system to do the name caching. - - this is an important implementational issue especially in the light - dynamic dns servers like dynip.com or dyndns.com where a dial - ip address is dynamically assigned a sub domain like farhan.dynip.com - - although expensive, this is a must to allow OS to take - the decision to expire the DNS records as it deems fit. - */ - pent = gethostbyname(host); - if (!pent) { - printf("'%s' is unresolveable\n", host); - exit_code(2, __PRETTY_FUNCTION__, "hostname is not resolveable"); - } - addr = *(uint32_t *) (pent->h_addr); - return addr; -} - -#ifdef HAVE_CARES_H -static const unsigned char *parse_rr(const unsigned char *aptr, const unsigned char *abuf, int alen) { - char *name; - long len; - int status, type, dnsclass, dlen; - struct in_addr addr; - - dbg("ca_tmpname: %s\n", ca_tmpname); - status = ares_expand_name(aptr, abuf, alen, &name, &len); - if (status != ARES_SUCCESS) { - printf("error: failed to expand query name\n"); - exit_code(2, __PRETTY_FUNCTION__, "failed to expand query name"); - } - aptr += len; - if (aptr + NS_RRFIXEDSZ > abuf + alen) { - printf("error: not enough data in DNS answer 1\n"); - free(name); - return NULL; - } - type = DNS_RR_TYPE(aptr); - dnsclass = DNS_RR_CLASS(aptr); - dlen = DNS_RR_LEN(aptr); - aptr += NS_RRFIXEDSZ; - if (aptr + dlen > abuf + alen) { - printf("error: not enough data in DNS answer 2\n"); - free(name); - return NULL; - } - if (dnsclass != CARES_CLASS_C_IN) { - printf("error: unsupported dnsclass (%i) in DNS answer\n", dnsclass); - free(name); - return NULL; - } - if (type != CARES_TYPE_SRV && type != CARES_TYPE_A && type != CARES_TYPE_CNAME) { - printf("error: unsupported DNS response type (%i)\n", type); - free(name); - return NULL; - } - if (type == CARES_TYPE_SRV) { - free(name); - caport = DNS__16BIT(aptr + 4); - dbg("caport: %i\n", caport); - status = ares_expand_name(aptr + 6, abuf, alen, &name, &len); - if (status != ARES_SUCCESS) { - printf("error: failed to expand SRV name\n"); - return NULL; - } - dbg("SRV name: %s\n", name); - if (is_ip(name)) { - caadr = inet_addr(name); - free(name); - } - else { - ca_tmpname = name; - } - } - else if (type == CARES_TYPE_CNAME) { - if ((ca_tmpname != NULL) && - (STRNCASECMP(ca_tmpname, name, strlen(ca_tmpname)) == 0)) { - ca_tmpname = malloc(strlen(name)); - if (ca_tmpname == NULL) { - printf("error: failed to allocate memory\n"); - exit_code(2, __PRETTY_FUNCTION__, "memory allocation failure"); - } - strcpy(ca_tmpname, name); - free(name); - } - else { - free(name); - status = ares_expand_name(aptr, abuf, alen, &name, &len); - if (status != ARES_SUCCESS) { - printf("error: failed to expand CNAME\n"); - return NULL; - } - dbg("CNAME: %s\n", name); - if (is_ip(name)) { - caadr = inet_addr(name); - free(name); - } - else { - ca_tmpname = name; - } - } - } - else if (type == CARES_TYPE_A) { - if (dlen == 4 && STRNCASECMP(ca_tmpname, name, strlen(ca_tmpname)) == 0) { - memcpy(&addr, aptr, sizeof(struct in_addr)); - caadr = addr.s_addr; - } - free(name); - } - return aptr + dlen; -} - -static const unsigned char *skip_rr(const unsigned char *aptr, const unsigned char *abuf, int alen) { - int status, dlen; - long len; - char *name; - - dbg("skipping rr section...\n"); - status = ares_expand_name(aptr, abuf, alen, &name, &len); - aptr += len; - dlen = DNS_RR_LEN(aptr); - aptr += NS_RRFIXEDSZ; - aptr += dlen; - free(name); - return aptr; -} - -static const unsigned char *skip_query(const unsigned char *aptr, const unsigned char *abuf, int alen) { - int status; - long len; - char *name; - - dbg("skipping query section...\n"); - status = ares_expand_name(aptr, abuf, alen, &name, &len); - aptr += len; - aptr += NS_QFIXEDSZ; - free(name); - return aptr; -} - -static void cares_callback(void *arg, int status, int timeouts, unsigned char *abuf, int alen) { - int i; - unsigned int ancount, nscount, arcount; - const unsigned char *aptr; - - dbg("cares_callback: status=%i, alen=%i\n", status, alen); - if (status != ARES_SUCCESS) { - if (verbose > 1) - printf("ares failed: %s\n", ares_strerror(status)); - return; - } - - ancount = DNS_HEADER_ANCOUNT(abuf); - nscount = DNS_HEADER_NSCOUNT(abuf); - arcount = DNS_HEADER_ARCOUNT(abuf); - - dbg("ancount: %i, nscount: %i, arcount: %i\n", ancount, nscount, arcount); - - /* safety check */ - if (alen < NS_HFIXEDSZ) - return; - aptr = abuf + NS_HFIXEDSZ; - - aptr = skip_query(aptr, abuf, alen); - - for (i = 0; i < ancount && caadr == 0; i++) { - if (ca_tmpname == NULL) - aptr = parse_rr(aptr, abuf, alen); - else - aptr = skip_rr(aptr, abuf, alen); - } - if (caadr == 0 && aptr != NULL) { - for (i = 0; i < nscount; i++) { - aptr = skip_rr(aptr, abuf, alen); - } - for (i = 0; i < arcount && caadr == 0; i++) { - aptr = parse_rr(aptr, abuf, alen); - } - } -} - -static inline unsigned long srv_ares(char *host, int *port, char *srv) { - int nfds, count, srvh_len; - char *srvh; - fd_set read_fds, write_fds; - struct timeval *tvp, tv; - - caport = 0; - caadr = 0; - ca_tmpname = NULL; - dbg("starting ARES query\n"); - - srvh_len = strlen(host) + strlen(srv) + 2; - srvh = malloc(srvh_len); - if (srvh == NULL) { - printf("error: failed to allocate memory (%i) for ares query\n", srvh_len); - exit_code(2, __PRETTY_FUNCTION__, "memory allocation failure"); - } - memset(srvh, 0, srvh_len); - strncpy(srvh, srv, strlen(srv)); - memcpy(srvh + strlen(srv), ".", 1); - strcpy(srvh + strlen(srv) + 1, host); - dbg("hostname: '%s', len: %i\n", srvh, srvh_len); - - ares_query(channel, srvh, CARES_CLASS_C_IN, CARES_TYPE_SRV, cares_callback, (char *) NULL); - dbg("ares_query finished, waiting for result...\n"); - /* wait for query to complete */ - while (1) { - FD_ZERO(&read_fds); - FD_ZERO(&write_fds); - nfds = ares_fds(channel, &read_fds, &write_fds); - if (nfds == 0) - break; - tvp = ares_timeout(channel, NULL, &tv); - count = select(nfds, &read_fds, &write_fds, NULL, tvp); - if (count < 0 && errno != EINVAL) { - perror("ares select"); - exit_code(2, __PRETTY_FUNCTION__, "ares DNS resolution failure"); - } - ares_process(channel, &read_fds, &write_fds); - } - dbg("ARES answer processed\n"); - *port = caport; - if (caadr == 0 && ca_tmpname != NULL) { - caadr = getaddress(ca_tmpname); - } - if (ca_tmpname != NULL) - free(ca_tmpname); - free(srvh); - return caadr; -} -#endif // HAVE_CARES_H - -#ifdef HAVE_RULI_H -static inline unsigned long srv_ruli(char *host, int *port, char *srv) { - int srv_code; - int ruli_opts = RULI_RES_OPT_SEARCH | RULI_RES_OPT_SRV_NOINET6 | RULI_RES_OPT_SRV_NOSORT6 | RULI_RES_OPT_SRV_NOFALL; -#ifdef RULI_RES_OPT_SRV_CNAME - ruli_opts |= RULI_RES_OPT_SRV_CNAME; -#endif - - ruli_sync_t *sync_query = ruli_sync_query(srv, host, *port, ruli_opts); - - /* sync query failure? */ - if (!sync_query) { - printf("DNS SRV lookup failed for: %s\n", host); - exit_code(2, __PRETTY_FUNCTION__, "DNS SRV lookup failed"); - } - - srv_code = ruli_sync_srv_code(sync_query); - /* timeout? */ - if (srv_code == RULI_SRV_CODE_ALARM) { - printf("Timeout during DNS SRV lookup for: %s\n", host); - ruli_sync_delete(sync_query); - exit_code(2, __PRETTY_FUNCTION__, "timeout during DNS SRV lookup"); - } - /* service provided? */ - else if (srv_code == RULI_SRV_CODE_UNAVAILABLE) { - printf("SRV service not provided for: %s\n", host); - ruli_sync_delete(sync_query); - exit_code(2, __PRETTY_FUNCTION__, "missing service in DNS SRV reply"); - } - else if (srv_code) { - int rcode = ruli_sync_rcode(sync_query); - if (verbose > 1) - printf("SRV query failed for: %s, srv_code=%d, rcode=%d\n", host, srv_code, rcode); - ruli_sync_delete(sync_query); - return 0; - } - - ruli_list_t *srv_list = ruli_sync_srv_list(sync_query); - - int srv_list_size = ruli_list_size(srv_list); - - if (srv_list_size < 1) { - if (verbose > 1) - printf("No SRV record: %s.%s\n", srv, host); - return 0; - } - - ruli_srv_entry_t *entry = (ruli_srv_entry_t *) ruli_list_get(srv_list, 0); - ruli_list_t *addr_list = &entry->addr_list; - int addr_list_size = ruli_list_size(addr_list); - - if (addr_list_size < 1) { - printf("missing addresses in SRV lookup for: %s\n", host); - ruli_sync_delete(sync_query); - exit_code(2, __PRETTY_FUNCTION__, "missing address in DNS SRV reply"); - } - - *port = entry->port; - ruli_addr_t *addr = (ruli_addr_t *) ruli_list_get(addr_list, 0); - return addr->addr.ipv4.s_addr; -} -#endif // HAVE_RULI_H - -unsigned long getsrvaddress(char *host, int *port, char *srv) { -#ifdef HAVE_RULI_H - return srv_ruli(host, port, srv); -#else -# ifdef HAVE_CARES_H // HAVE_RULI_H - return srv_ares(host, port, srv); -# else // HAVE_CARES_H - return 0; -# endif -#endif -} - -/* Finds the SRV records for the given host. It returns the target IP - * address and fills the port and transport if a suitable SRV record - * exists. Otherwise it returns 0. The function follows 3263: first - * TLS, then TCP and finally UDP. */ -unsigned long getsrvadr(char *host, int *port, unsigned int *transport) { - unsigned long adr = 0; - -#ifdef HAVE_SRV - int srvport = 5060; - -#ifdef HAVE_CARES_H - int status; - int optmask = ARES_OPT_FLAGS; - struct ares_options options; - - options.flags = ARES_FLAG_NOCHECKRESP; - options.servers = NULL; - options.nservers = 0; - - status = ares_init_options(&channel, &options, optmask); - if (status != ARES_SUCCESS) { - printf("error: failed to initialize ares\n"); - exit_code(2, __PRETTY_FUNCTION__, "failed to init ares lib"); - } -#endif - -#ifdef WITH_TLS_TRANSP - adr = getsrvaddress(host, &srvport, SRV_SIP_TLS); - if (adr != 0) { - *transport = SIP_TLS_TRANSPORT; - if (verbose > 1) - printf("using SRV record: %s.%s:%i\n", SRV_SIP_TLS, host, srvport); - } - else { -#endif - adr = getsrvaddress(host, &srvport, SRV_SIP_TCP); - if (adr != 0) { - *transport = SIP_TCP_TRANSPORT; - if (verbose > 1) - printf("using SRV record: %s.%s:%i\n", SRV_SIP_TCP, host, srvport); - } - else { - adr = getsrvaddress(host, &srvport, SRV_SIP_UDP); - if (adr != 0) { - *transport = SIP_UDP_TRANSPORT; - if (verbose > 1) - printf("using SRV record: %s.%s:%i\n", SRV_SIP_UDP, host, srvport); - } - } -#ifdef WITH_TLS_TRANSP - } -#endif - -#ifdef HAVE_CARES_H - ares_destroy(channel); -#endif - - *port = srvport; -#endif // HAVE_SRV - return adr; -} - -/* because the full qualified domain name is needed by many other - functions it will be determined by this function. -*/ -void get_fqdn() { - char hname[100], dname[100], hlp[18]; - size_t namelen=100; - struct hostent* he; - struct utsname un; - - memset(&hname, 0, sizeof(hname)); - memset(&dname, 0, sizeof(dname)); - memset(&hlp, 0, sizeof(hlp)); - - if (hostname) { - strncpy(fqdn, hostname, FQDN_SIZE-1); - strncpy(hname, hostname, sizeof(hname)-1); - } - else { - if ((uname(&un))==0) { - strncpy(hname, un.nodename, sizeof(hname)-1); - } - else { - if (gethostname(&hname[0], namelen) < 0) { - fprintf(stderr, "error: cannot determine hostname\n"); - exit_code(2, __PRETTY_FUNCTION__, "failed to determine hostname"); - } - } -#ifdef HAVE_GETDOMAINNAME - /* a hostname with dots should be a domainname */ - if ((strchr(hname, '.'))==NULL) { - if (getdomainname(&dname[0], namelen) < 0) { - fprintf(stderr, "error: cannot determine domainname\n"); - exit_code(2, __PRETTY_FUNCTION__, "failed to get domainname"); - } - if (strcmp(&dname[0],"(none)")!=0) - snprintf(fqdn, FQDN_SIZE, "%s.%s", hname, dname); - } - else { - strncpy(fqdn, hname, FQDN_SIZE-1); - } -#endif - } - - if (!(numeric == 1 && is_ip(fqdn))) { - he=gethostbyname(hname); - if (he) { - if (numeric == 1) { - snprintf(hlp, sizeof(hlp), "%s", inet_ntoa(*(struct in_addr *) he->h_addr_list[0])); - strncpy(fqdn, hlp, FQDN_SIZE-1); - } - else { - if ((strchr(he->h_name, '.'))!=NULL && (strchr(hname, '.'))==NULL) { - strncpy(fqdn, he->h_name, FQDN_SIZE-1); - } - else { - strncpy(fqdn, hname, FQDN_SIZE-1); - } - } - } - else { - fprintf(stderr, "error: cannot resolve local hostname: %s\n", hname); - exit_code(2, __PRETTY_FUNCTION__, "failed to resolve local hostname"); - } - } - if ((strchr(fqdn, '.'))==NULL) { - if (hostname) { - fprintf(stderr, "warning: %s is not resolvable... continouing anyway\n", fqdn); - strncpy(fqdn, hostname, FQDN_SIZE-1); - } - else { - fprintf(stderr, "error: this FQDN or IP is not valid: %s\n", fqdn); - exit_code(2, __PRETTY_FUNCTION__, "invalid IP or FQDN"); - } - } - - if (verbose > 2) - printf("fqdnhostname: %s\n", fqdn); -} - -/* this function searches for search in mess and replaces it with - replacement */ -void replace_string(char *mess, char *search, char *replacement) { - char *backup, *insert; - - insert=STRCASESTR(mess, search); - if (insert==NULL){ - if (verbose > 2) - fprintf(stderr, "warning: could not find this '%s' replacement string in " - "message\n", search); - } - else { - while (insert){ - backup=str_alloc(strlen(insert)+1); - strcpy(backup, insert+strlen(search)); - strcpy(insert, replacement); - strcpy(insert+strlen(replacement), backup); - free(backup); - insert=STRCASESTR(mess, search); - } - } -} - -/* checks if the strings contains special double marks and then - * replace all occurrences of this strings in the message */ -void replace_strings(char *mes, char *strings) { - char *pos, *atr, *val, *repl, *end; - char sep; - - pos=atr=val=repl = NULL; - dbg("replace_strings entered\nstrings: '%s'\n", strings); - if ((isalnum(*strings) != 0) && - (isalnum(*(strings + strlen(strings) - 1)) != 0)) { - replace_string(req, "$replace$", replace_str); - } - else { - sep = *strings; - dbg("sep: '%c'\n", sep); - end = strings + strlen(strings); - pos = strings + 1; - while (pos < end) { - atr = pos; - pos = strchr(atr, sep); - if (pos != NULL) { - *pos = '\0'; - val = pos + 1; - pos = strchr(val, sep); - if (pos != NULL) { - *pos = '\0'; - pos++; - } - } - dbg("atr: '%s'\nval: '%s'\n", atr, val); - if ((atr != NULL) && (val != NULL)) { - repl = str_alloc(strlen(val) + 3); - if (repl == NULL) { - printf("failed to allocate memory\n"); - exit_code(2, __PRETTY_FUNCTION__, "memory allocation failure"); - } - sprintf(repl, "$%s$", atr); - replace_string(mes, repl, val); - free(repl); - } - dbg("pos: '%s'\n", pos); - } - } - dbg("mes:\n'%s'\n", mes); -} - -/* insert \r in front of all \n if it is not present already - * and and a trailing \r\n is not present */ -void insert_cr(char *mes) { - char *lf, *pos, *backup; - - pos = mes; - lf = strchr(pos, '\n'); - while ((lf != NULL) && (lf >= mes+1) && (*(--lf) != '\r')) { - backup=str_alloc(strlen(lf)+2); - strcpy(backup, lf+1); - *(lf+1) = '\r'; - strcpy(lf+2, backup); - free(backup); - pos = lf+3; - lf = strchr(pos, '\n'); - } - lf = STRCASESTR(mes, "\r\n\r\n"); - if (lf == NULL) { - lf = mes + strlen(mes); - sprintf(lf, "\r\n"); - } -} - -/* sipmly swappes the content of the two buffers */ -void swap_buffers(char *fst, char *snd) { - char *tmp; - - if (fst == snd) - return; - tmp = str_alloc(strlen(fst)+1); - strcpy(tmp, fst); - strcpy(fst, snd); - strcpy(snd, tmp); - free(tmp); -} - -void swap_ptr(char **fst, char **snd) { - char *tmp; - - tmp = *fst; - *fst = *snd; - *snd = tmp; -} - -/* trashes one character in buff randomly */ -void trash_random(char *message) { - int r; - float t; - char *position; - - t=(float)rand()/RAND_MAX; - r=(int)(t * (float)strlen(message)); - position=message+r; - r=(int)(t*(float)255); - *position=(char)r; - if (verbose > 2) - printf("request:\n%s\n", message); -} - -/* this function is taken from traceroute-1.4_p12 - which is distributed under the GPL and it returns - the difference between to timeval structs */ -double deltaT(struct timeval *t1p, struct timeval *t2p) { - register double dt; - - dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + - (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; - return (dt); -} - -/* returns one if the string contains only numbers otherwise zero */ -int is_number(char *number) { - int digit = 1; - if (strlen(number) == 0) { - return 0; - } - while (digit && (*number != '\0')) { - digit = isdigit(*number); - number++; - } - return digit ? 1 : 0; -} - -/* tries to convert the given string into an integer. it strips - * white-spaces and exits if an error happens */ -int str_to_int(int mode, char *num) { - int ret, len; - char *end, *start; - char *backup = NULL; - - len = strlen(num); - if (len == 0) { - fprintf(stderr, "error: string has zero length: '%s'\n", num); - ret = 2; - goto error; - } - /* we need to make a backup to insert the zero char */ - backup = malloc(len + 1); - if (!backup) { - fprintf(stderr, "error: failed to allocate memory\n"); - ret = 2; - goto error; - } - memcpy(backup, num, len + 1); - - start = backup; - end = backup + len; - while (isspace(*start) && (start < end)) { - start++; - } - if (start == end) { - fprintf(stderr, "error: string is too short: '%s'\n", num); - ret = 2; - goto error; - } - if (mode == 0) { - end--; - while (isspace(*end) && (end > start)) { - end--; - } - if (end != (backup + len - 1)) { - end++; - *end = '\0'; - } - } - else { - end = start; - end++; - while ((end < backup + len) && *end != '\0' && !isspace(*end)) { - end++; - } - *end = '\0'; - } - if (!is_number(start)) { - fprintf(stderr, "error: string is not a number: '%s'\n", start); - ret = 2; - goto error; - } - ret = atoi(start); - if (ret >= 0) { - free(backup); - return ret; - } - else { - fprintf(stderr, "error: failed to convert string to integer: '%s'\n", num); - ret = 2; - } -error: - if (backup) { - free(backup); - } - if (mode == 0) { - /* libcheck expects a return value not an exit code */ -#ifndef RUNNING_CHECK - exit_code(ret, __PRETTY_FUNCTION__, NULL); -#endif - } - return (ret * - 1); -} - -/* reads into the given buffer from standard input until the EOF - * character, LF character or the given size of the buffer is exceeded */ -int read_stdin(char *buf, int size, int ret) { - int i, j; - - for(i = 0; i < size - 1; i++) { - j = getchar(); - if (((ret == 0) && (j == EOF)) || - ((ret == 1) && (j == '\n'))) { - *(buf + i) = '\0'; - return i; - } - else { - *(buf + i) = j; - } - } - *(buf + i) = '\0'; - if (verbose) - fprintf(stderr, "warning: readin buffer size exceeded\n"); - return i; -} - -/* tries to allocate the given size of memory and sets it all to zero. - * if the allocation fails it exits */ -void *str_alloc(size_t size) { - char *ptr; -#ifdef HAVE_CALLOC - ptr = calloc(1, size); -#else - ptr = malloc(size); -#endif - if (ptr == NULL) { - fprintf(stderr, "error: memory allocation failed\n"); - exit_code(255, __PRETTY_FUNCTION__, "memory allocation failure"); - } -#ifndef HAVE_CALLOC - memset(ptr, 0, size); -#endif - return ptr; -} - -void dbg(char* format, ...) { -#ifdef DEBUG - va_list ap; - - fprintf(stderr, "DEBUG: "); - va_start(ap, format); - vfprintf(stderr, format, ap); - fflush(stderr); - va_end(ap); -#endif -} diff -Nru sipsak-0.9.6+git20170713/helper.h sipsak-0.9.7/helper.h --- sipsak-0.9.6+git20170713/helper.h 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/helper.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2002-2004 Fhg Fokus - * Copyright (C) 2004-2005 Nils Ohlmeier - * - * This file belongs to sipsak, a free sip testing tool. - * - * sipsak is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * sipsak is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef SIPSAK_HELPER_H -#define SIPSAK_HELPER_H - -#include "sipsak.h" - -#ifdef HAVE_SYS_TIME_H -# include -#else -# include -#endif -#ifdef HAVE_SYS_SELECT_H -# include -#endif - -#ifdef HAVE_CARES_H -# define HAVE_SRV -#else -# ifdef HAVE_RULI_H -# define HAVE_SRV -# endif -#endif - -#ifdef HAVE_CARES_H -# define CARES_TYPE_A 1 -# define CARES_TYPE_CNAME 5 -# define CARES_TYPE_SRV 33 -# define CARES_CLASS_C_IN 1 -/* copied from ares_dns.h */ -# define DNS__16BIT(p) (((p)[0] << 8) | (p)[1]) -# define DNS_HEADER_ANCOUNT(h) DNS__16BIT((h) + 6) -# define DNS_HEADER_NSCOUNT(h) DNS__16BIT((h) + 8) -# define DNS_HEADER_ARCOUNT(h) DNS__16BIT((h) + 10) -# define DNS_RR_TYPE(r) DNS__16BIT(r) -# define DNS_RR_CLASS(r) DNS__16BIT((r) + 2) -# define DNS_RR_LEN(r) DNS__16BIT((r) + 8) -#endif - -#ifdef HAVE_SRV -# define SRV_SIP_TLS "_sip._tls" -# define SRV_SIP_TCP "_sip._tcp" -# define SRV_SIP_UDP "_sip._udp" -#endif - -int is_ip(char *str); - -unsigned long getaddress(char *host); - -unsigned long getsrvadr(char *host, int *port, unsigned int *transport); - -void get_fqdn(); - -void replace_string(char *mes, char *search, char *replacement); - -void replace_strings(char *mes, char *strings); - -void insert_cr(char *mes); - -void swap_buffers(char *fst, char *snd); - -void swap_ptr(char **fst, char **snd); - -void trash_random(char *message); - -double deltaT(struct timeval *t1p, struct timeval *t2p); - -int is_number(char *number); - -int str_to_int(int mode, char *num); - -int read_stdin(char *buf, int size, int ret); - -void *str_alloc(size_t size); - -void dbg(char* format, ...); -#endif diff -Nru sipsak-0.9.6+git20170713/Makefile.am sipsak-0.9.7/Makefile.am --- sipsak-0.9.6+git20170713/Makefile.am 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/Makefile.am 2019-04-27 04:54:34.000000000 +0000 @@ -2,8 +2,26 @@ CC = ${DISTCC} @CC@ -SUBDIRS = . tests +bin_PROGRAMS = sipsak + +TRANSPORT_SOURCES = src/transport.c src/transport.h + +sipsak_SOURCES = $(TRANSPORT_SOURCES) src/auth.c src/auth.h src/header_f.c src/header_f.h src/helper.c src/helper.h src/md5.c src/md5.h src/md5global.h src/request.c src/request.h src/shoot.c src/shoot.h src/sipsak.c src/sipsak.h src/exit_code.h src/exit_code.c -bin_PROGRAMS=sipsak -sipsak_SOURCES=auth.c auth.h header_f.c header_f.h helper.c helper.h md5.c md5.h md5global.h request.c request.h shoot.c shoot.h sipsak.c sipsak.h exit_code.h exit_code.c transport.c transport.h dist_man1_MANS=sipsak.1 + +# Tests + +TESTS = tests/check_helper tests/check_md5 + +check_PROGRAMS = $(TESTS) + +tests_check_helper_SOURCES = tests/check_helper.c src/helper.h src/helper.c src/exit_code.h src/exit_code.c +tests_check_helper_CFLAGS = @CHECK_CFLAGS@ -DRUNNING_CHECK +tests_check_helper_LDADD = @CHECK_LIBS@ + +tests_check_md5_SOURCES = tests/check_md5.c src/md5.h src/md5.c +tests_check_md5_CFLAGS = @CHECK_CFLAGS@ -DRUNNING_CHECK +tests_check_md5_LDADD = @CHECK_LIBS@ + +FAKE_TRANSPORT_SOURCES = tests/fake_transport.c src/transport.h diff -Nru sipsak-0.9.6+git20170713/md5.c sipsak-0.9.7/md5.c --- sipsak-0.9.6+git20170713/md5.c 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/md5.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,362 +0,0 @@ -/* - -MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm - -Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All -rights reserved. - -License to copy and use this software is granted provided that it -is identified as the "RSA Data Security, Inc. MD5 Message-Digest -Algorithm" in all material mentioning or referencing this software -or this function. - -License is also granted to make and use derivative works provided -that such works are identified as "derived from the RSA Data -Security, Inc. MD5 Message-Digest Algorithm" in all material -mentioning or referencing the derived work. - -RSA Data Security, Inc. makes no representations concerning either -the merchantability of this software or the suitability of this -software for any particular purpose. It is provided "as is" -without express or implied warranty of any kind. - -These notices must be retained in any copies of any part of this -documentation and/or software. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "md5.h" - -#ifndef HAVE_EXTERNAL_MD5 - -#ifdef HAVE_STRING_H -# include -#endif - -#define USE_MEM - -/* Constants for MD5Transform routine. - */ - - - - -#define S11 7 -#define S12 12 -#define S13 17 -#define S14 22 -#define S21 5 -#define S22 9 -#define S23 14 -#define S24 20 -#define S31 4 -#define S32 11 -#define S33 16 -#define S34 23 -#define S41 6 -#define S42 10 -#define S43 15 -#define S44 21 - -static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64])); -static void Encode PROTO_LIST - ((unsigned char *, UINT4 *, unsigned int)); -static void Decode PROTO_LIST - ((UINT4 *, unsigned char *, unsigned int)); -static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int)); -static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int)); - -static unsigned char PADDING[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* F, G, H and I are basic MD5 functions. - */ -#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) -#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define I(x, y, z) ((y) ^ ((x) | (~z))) - -/* ROTATE_LEFT rotates x left n bits. - */ -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) - -/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. -Rotation is separate from addition to prevent recomputation. - */ -#define FF(a, b, c, d, x, s, ac) { \ - (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define GG(a, b, c, d, x, s, ac) { \ - (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define HH(a, b, c, d, x, s, ac) { \ - (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define II(a, b, c, d, x, s, ac) { \ - (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } - -/* MD5 initialization. Begins an MD5 operation, writing a new context. - */ -void MD5Init (context) -MD5_CTX *context; /* context */ -{ - context->count[0] = context->count[1] = 0; - /* Load magic initialization constants. -*/ - context->state[0] = 0x67452301; - context->state[1] = 0xefcdab89; - context->state[2] = 0x98badcfe; - context->state[3] = 0x10325476; -} - -/* MD5 block update operation. Continues an MD5 message-digest - operation, processing another message block, and updating the - context. - */ -void MD5Update (context, input, inputLen) -MD5_CTX *context; /* context */ -unsigned char *input; /* input block */ -unsigned int inputLen; /* length of input block */ -{ - unsigned int i, index, partLen; - - /* Compute number of bytes mod 64 */ - index = (unsigned int)((context->count[0] >> 3) & 0x3F); - - /* Update number of bits */ - if ((context->count[0] += ((UINT4)inputLen << 3)) - - < ((UINT4)inputLen << 3)) - context->count[1]++; - context->count[1] += ((UINT4)inputLen >> 29); - - partLen = 64 - index; - - /* Transform as many times as possible. -*/ - if (inputLen >= partLen) { - MD5_memcpy - ((POINTER)&context->buffer[index], (POINTER)input, partLen); - MD5Transform (context->state, context->buffer); - - for (i = partLen; i + 63 < inputLen; i += 64) - MD5Transform (context->state, &input[i]); - - index = 0; - } - else - i = 0; - - /* Buffer remaining input */ - MD5_memcpy - ((POINTER)&context->buffer[index], (POINTER)&input[i], - inputLen-i); -} - -/* MD5 finalization. Ends an MD5 message-digest operation, writing the - the message digest and zeroizing the context. - */ -void MD5Final (digest, context) -unsigned char digest[16]; /* message digest */ -MD5_CTX *context; /* context */ -{ - unsigned char bits[8]; - unsigned int index, padLen; - - /* Save number of bits */ - Encode (bits, context->count, 8); - - /* Pad out to 56 mod 64. -*/ - index = (unsigned int)((context->count[0] >> 3) & 0x3f); - padLen = (index < 56) ? (56 - index) : (120 - index); - MD5Update (context, PADDING, padLen); - - /* Append length (before padding) */ - MD5Update (context, bits, 8); - - /* Store state in digest */ - Encode (digest, context->state, 16); - - /* Zeroize sensitive information. -*/ - MD5_memset ((POINTER)context, 0, sizeof (*context)); -} - -/* MD5 basic transformation. Transforms state based on block. - */ -static void MD5Transform (state, block) -UINT4 state[4]; -unsigned char block[64]; -{ - UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; - - Decode (x, block, 64); - - /* Round 1 */ - FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ - FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ - FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ - FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ - FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ - FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ - FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ - FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ - FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ - FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ - FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ - FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ - FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ - FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ - FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ - FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ - - /* Round 2 */ - GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ - GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ - GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ - GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ - GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ - GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ - GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ - GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ - GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ - GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ - GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ - GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ - GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ - GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ - GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ - GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ - - /* Round 3 */ - HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ - HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ - HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ - HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ - HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ - HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ - HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ - HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ - HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ - HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ - HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ - HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ - HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ - HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ - HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ - HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ - - /* Round 4 */ - II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ - II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ - II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ - II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ - II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ - II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ - II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ - II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ - II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ - II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ - II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ - II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ - II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ - II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ - II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ - II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ - - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - - /* Zeroize sensitive information. -*/ - MD5_memset ((POINTER)x, 0, sizeof (x)); -} - -/* Encodes input (UINT4) into output (unsigned char). Assumes len is - a multiple of 4. - */ -static void Encode (output, input, len) -unsigned char *output; -UINT4 *input; -unsigned int len; -{ - unsigned int i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) { - output[j] = (unsigned char)(input[i] & 0xff); - output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); - output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); - output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); - } -} - -/* Decodes input (unsigned char) into output (UINT4). Assumes len is - a multiple of 4. - */ -static void Decode (output, input, len) -UINT4 *output; -unsigned char *input; -unsigned int len; -{ - unsigned int i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) - output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | - (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); -} - -/* Note: Replace "for loop" with standard memcpy if possible. - */ - -static void MD5_memcpy (output, input, len) -POINTER output; -POINTER input; -unsigned int len; -{ - -#ifndef USE_MEM - unsigned int i; - - for (i = 0; i < len; i++) - output[i] = input[i]; -#else - memcpy( output, input, len ); -#endif -} - -/* Note: Replace "for loop" with standard memset if possible. - */ -static void MD5_memset (output, value, len) -POINTER output; -int value; -unsigned int len; -{ - -#ifndef USE_MEM - unsigned int i; - for (i = 0; i < len; i++) - ((char *)output)[i] = (char)value; -#else - memset( output, value, len ); -#endif -} - -#endif /* ! HAVE_EXTERNAL_MD5 */ diff -Nru sipsak-0.9.6+git20170713/md5global.h sipsak-0.9.7/md5global.h --- sipsak-0.9.6+git20170713/md5global.h 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/md5global.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -/* GLOBAL.H - RSAREF types and constants - * - */ - - -/* PROTOTYPES should be set to one if and only if the compiler supports - function argument prototyping. -The following makes PROTOTYPES default to 0 if it has not already - been defined with C compiler flags. - */ -#ifndef PROTOTYPES -#define PROTOTYPES 0 -#endif - -/* POINTER defines a generic pointer type */ -typedef unsigned char *POINTER; - -#ifdef HAVE_STDINT_H -# include -typedef uint32_t UINT4; -#else -/* UINT4 defines a four byte word */ -typedef unsigned long int UINT4; -#endif - -/* PROTO_LIST is defined depending on how PROTOTYPES is defined above. -If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it - returns an empty list. - */ -#if PROTOTYPES -#define PROTO_LIST(list) list -#else -#define PROTO_LIST(list) () -#endif - diff -Nru sipsak-0.9.6+git20170713/md5.h sipsak-0.9.7/md5.h --- sipsak-0.9.6+git20170713/md5.h 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/md5.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -/* MD5.H - header file for MD5C.C - */ - - -/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All -rights reserved. - -License to copy and use this software is granted provided that it -is identified as the "RSA Data Security, Inc. MD5 Message-Digest -Algorithm" in all material mentioning or referencing this software -or this function. - -License is also granted to make and use derivative works provided -that such works are identified as "derived from the RSA Data -Security, Inc. MD5 Message-Digest Algorithm" in all material -mentioning or referencing the derived work. - -RSA Data Security, Inc. makes no representations concerning either -the merchantability of this software or the suitability of this -software for any particular purpose. It is provided "as is" -without express or implied warranty of any kind. - -These notices must be retained in any copies of any part of this -documentation and/or software. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "sipsak.h" - -#ifdef HAVE_FULL_OPENSSL -# include -#endif - -#ifdef HAVE_EXTERNAL_MD5 - -# define MD5Init MD5_Init -# define MD5Update MD5_Update -# define MD5Final MD5_Final - -#else - -#include "md5global.h" - -/* MD5 context. */ -typedef struct { - UINT4 state[4]; /* state (ABCD) */ - UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ - unsigned char buffer[64]; /* input buffer */ -} MD5_CTX; - -void MD5Init PROTO_LIST ((MD5_CTX *)); -void MD5Update PROTO_LIST - ((MD5_CTX *, unsigned char *, unsigned int)); -void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); -#endif diff -Nru sipsak-0.9.6+git20170713/request.c sipsak-0.9.7/request.c --- sipsak-0.9.6+git20170713/request.c 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/request.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,326 +0,0 @@ -/* - * Copyright (C) 2002-2004 Fhg Fokus - * Copyright (C) 2004-2005 Nils Ohlmeier - * - * This file belongs to sipsak, a free sip testing tool. - * - * sipsak is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * sipsak is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "sipsak.h" - -#ifdef HAVE_STRING_H -# include -#endif - -#include "request.h" -#include "exit_code.h" -#include "helper.h" -#include "header_f.h" - -/* create a valid sip header for the different modes */ -void create_msg(int action, char *req_buff, char *repl_buff, char *username, int cseq){ - unsigned int c, d, len; - char *req_buf_begin = req_buff; - - if(cseq == 0) { - fprintf(stderr, "error: CSeq 0 is not allowed\n"); - exit_code(253, __PRETTY_FUNCTION__, "invalid CSeq 0"); - } - if (req_buff == NULL) - abort(); - if (username == NULL) - username = ""; - c=(unsigned int)rand(); - c+=lport; - d=(unsigned int)rand(); - switch (action){ - case REQ_REG: - sprintf(req_buff, - "%s sip:%s%s" - "%ssip:%s%s;tag=%x\r\n" - "%ssip:%s%s\r\n" - "%s%u@%s\r\n" - "%s%i %s\r\n" - "%s0\r\n" - "%s70\r\n" - "%s%s\r\n", - REG_STR, domainname, SIP20_STR, - FROM_STR, username, domainname, c, - TO_STR, username, domainname, - CALL_STR, c, fqdn, - CSEQ_STR, cseq, REG_STR, - CON_LEN_STR, - MAX_FRW_STR, - UA_STR, UA_VAL_STR); - req_buff += strlen(req_buff); - if (contact_uri!=NULL) { - sprintf(req_buff, "%s%i\r\n" - "%s%s\r\n\r\n", - EXP_STR, expires_t, - CONT_STR, contact_uri); - } - else if (empty_contact == 0) { - sprintf(req_buff, "%s%i\r\n" - "%ssip:%s%s:%i", - EXP_STR, expires_t, - CONT_STR, username, fqdn, lport); - req_buff += strlen(req_buff); - if (transport != SIP_UDP_TRANSPORT) - sprintf(req_buff, "%s%s\r\n\r\n", TRANSPORT_PARAMETER_STR, - transport_str); - else - sprintf(req_buff, "\r\n\r\n"); - } - else{ - sprintf(req_buff, "\r\n"); - } - add_via(req_buf_begin); - break; - case REQ_REM: - sprintf(req_buff, - "%s sip:%s%s" - "%ssip:%s%s;tag=%x\r\n" - "%ssip:%s%s\r\n" - "%s%u@%s\r\n" - "%s%i %s\r\n" - "%s%i\r\n" - "%s0\r\n" - "%s70\r\n" - "%s%s\r\n" - "%ssip:%s%s:%i;%s0", - REG_STR, domainname, SIP20_STR, - FROM_STR, username, domainname, c, - TO_STR, username, domainname, - CALL_STR, c, fqdn, - CSEQ_STR, cseq, REG_STR, - EXP_STR, expires_t, - CON_LEN_STR, - MAX_FRW_STR, - UA_STR, UA_VAL_STR, - CONT_STR, username, fqdn, lport, CON_EXP_STR); - req_buff += strlen(req_buff); - if (transport != SIP_UDP_TRANSPORT) { - sprintf(req_buff, "\r\n\r\n"); - } - else { - sprintf(req_buff, "%s%s\r\n\r\n", TRANSPORT_PARAMETER_STR, - transport_str); - } - add_via(req_buf_begin); - break; - case REQ_INV: - sprintf(req_buff, - "%s sip:%s%s%s" - "%ssip:%s%s\r\n" - "%s%u@%s\r\n" - "%s%i %s\r\n" - "%s0\r\n" - "%ssip:sipsak@%s:%i\r\n" - "%sDONT ANSWER this test call!\r\n" - "%s70\r\n" - "%s%s\r\n", - INV_STR, username, domainname, SIP20_STR, - TO_STR, username, domainname, - CALL_STR, c, fqdn, - CSEQ_STR, cseq, INV_STR, - CON_LEN_STR, - CONT_STR, fqdn, lport, - SUB_STR, - MAX_FRW_STR, - UA_STR, UA_VAL_STR); - req_buff += strlen(req_buff); - if (from_uri) { - sprintf(req_buff, - "%s%s;tag=%x\r\n" - "\r\n", - FROM_STR, from_uri, c); - } - else { - sprintf(req_buff, - "%ssip:sipsak@%s:%i;tag=%x\r\n" - "\r\n", - FROM_STR, fqdn, lport, c); - } - add_via(req_buf_begin); - sprintf(repl_buff, - "%s" - "%ssip:sipsak@%s:%i;tag=%x\r\n" - "%ssip:%s%s;tag=%o%o\r\n" - "%s%u@%s\r\n" - "%s%i %s\r\n" - "%s0\r\n" - "%ssip:sipsak_conf@%s:%i\r\n" - "%s%s\r\n" - "\r\n", - SIP200_STR, - FROM_STR, fqdn, lport, c, - TO_STR, username, domainname, c, d, - CALL_STR, c, fqdn, - CSEQ_STR, cseq, INV_STR, - CON_LEN_STR, - CONT_STR, fqdn, lport, - UA_STR, UA_VAL_STR); - break; - case REQ_MES: - sprintf(req_buff, - "%s sip:%s%s%s" - "%ssip:%s%s\r\n" - "%s%u@%s\r\n" - "%s%i %s\r\n" - "%s%s\r\n" - "%s70\r\n" - "%s%s\r\n", - MES_STR, username, domainname, SIP20_STR, - TO_STR, username, domainname, - CALL_STR, c, fqdn, - CSEQ_STR, cseq, MES_STR, - CON_TYP_STR, TXT_PLA_STR, - MAX_FRW_STR, - UA_STR, UA_VAL_STR); - req_buff += strlen(req_buff); - if (from_uri) { - sprintf(req_buff, - "%s%s;tag=%x\r\n", - FROM_STR, from_uri, c); - } - else { - sprintf(req_buff, - "%ssip:sipsak@%s:%i;tag=%x\r\n", - FROM_STR, fqdn, lport, c); - } - req_buff += strlen(req_buff); - if (mes_body) { - len = strlen(mes_body); - } - else { - len = SIPSAK_MES_STR_LEN + strlen(username); - } - sprintf(req_buff, "%s%u\r\n", CON_LEN_STR, len); - req_buff += strlen(req_buff); - if (con_dis) { - sprintf(req_buff, "%s%s\r\n", CON_DIS_STR, con_dis); - req_buff += strlen(req_buff); - } - sprintf(req_buff, "\r\n"); - req_buff += 2; - if (mes_body) { - sprintf(req_buff, - "%s", - mes_body); - } - else { - sprintf(req_buff, "%s%s", SIPSAK_MES_STR, username); - req_buff += strlen(req_buff) - 1; - *(req_buff) = '.'; - } - add_via(req_buf_begin); - sprintf(repl_buff, - "%s" - "%ssip:sipsak@%s:%i;tag=%x\r\n" - "%ssip:%s%s;tag=%o%o\r\n" - "%s%u@%s\r\n" - "%s%i %s\r\n" - "%s0\r\n" - "%s%s\r\n" - "\r\n", - SIP200_STR, - FROM_STR, fqdn, lport, c, - TO_STR, username, domainname, c, d, - CALL_STR, c, fqdn, - CSEQ_STR, cseq, MES_STR, - CON_LEN_STR, - UA_STR, UA_VAL_STR); - break; - case REQ_OPT: - sprintf(req_buff, - "%s sip:%s%s%s" - "%ssip:sipsak@%s:%i;tag=%x\r\n" - "%ssip:%s%s\r\n" - "%s%u@%s\r\n" - "%s%i %s\r\n" - "%ssip:sipsak@%s:%i\r\n" - "%s0\r\n" - "%s70\r\n" - "%s%s\r\n" - "%s%s\r\n" - "\r\n", - OPT_STR, username, domainname, SIP20_STR, - FROM_STR, fqdn, lport, c, - TO_STR, username, domainname, - CALL_STR, c, fqdn, - CSEQ_STR, cseq, OPT_STR, - CONT_STR, fqdn, lport, - CON_LEN_STR, - MAX_FRW_STR, - UA_STR, UA_VAL_STR, - ACP_STR, TXT_PLA_STR); - add_via(req_buf_begin); - break; - case REQ_FLOOD: - sprintf(req_buff, - "%s sip:%s%s%s" - "%s%s %s:9;branch=z9hG4bK.%08x\r\n" - "%ssip:sipsak@%s:9;tag=%x\r\n" - "%ssip:%s%s\r\n" - "%s%u@%s\r\n" - "%s%i %s\r\n" - "%ssip:sipsak@%s:9\r\n" - "%s0\r\n" - "%s70\r\n" - "%s%s\r\n" - "\r\n", - FLOOD_METH, username, domainname, SIP20_STR, - VIA_SIP_STR, TRANSPORT_UDP_STR, fqdn, d, - FROM_STR, fqdn, c, - TO_STR, username, domainname, - CALL_STR, c, fqdn, - CSEQ_STR, cseq, FLOOD_METH, - CONT_STR, fqdn, - CON_LEN_STR, - MAX_FRW_STR, - UA_STR, UA_VAL_STR); - break; - case REQ_RAND: - sprintf(req_buff, - "%s sip:%s%s" - "%ssip:sipsak@%s:%i;tag=%x\r\n" - "%ssip:%s\r\n" - "%s%u@%s\r\n" - "%s%i %s\r\n" - "%ssipsak@%s:%i\r\n" - "%s0\r\n" - "%s70\r\n" - "%s%s\r\n" - "\r\n", - OPT_STR, domainname, SIP20_STR, - FROM_STR, fqdn, lport, c, - TO_STR, domainname, - CALL_STR, c, fqdn, - CSEQ_STR, cseq, OPT_STR, - CONT_STR, fqdn, lport, - CON_LEN_STR, - MAX_FRW_STR, - UA_STR, UA_VAL_STR); - add_via(req_buf_begin); - break; - default: - fprintf(stderr, "error: unknown request type to create\n"); - exit_code(2, __PRETTY_FUNCTION__, "unknown request type requested"); - break; - } - if (headers) { - insert_header(req_buf_begin, headers, 1); - if (repl_buff) - insert_header(repl_buff, headers, 1); - } -} - diff -Nru sipsak-0.9.6+git20170713/request.h sipsak-0.9.7/request.h --- sipsak-0.9.6+git20170713/request.h 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/request.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2002-2004 Fhg Fokus - * Copyright (C) 2004-2005 Nils Ohlmeier - * - * This file belongs to sipsak, a free sip testing tool. - * - * sipsak is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * sipsak is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef SIPSAK_REQUEST_H -#define SIPSAK_REQUEST_H - -void create_msg(int action, char *buff, char *repl_buff, char *username, int cseq); - -#endif diff -Nru sipsak-0.9.6+git20170713/shoot.c sipsak-0.9.7/shoot.c --- sipsak-0.9.6+git20170713/shoot.c 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/shoot.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1107 +0,0 @@ -/* - * Copyright (C) 2002-2004 Fhg Fokus - * Copyright (C) 2004-2005 Nils Ohlmeier - * - * This file belongs to sipsak, a free sip testing tool. - * - * sipsak is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * sipsak is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "sipsak.h" - -#ifdef TIME_WITH_SYS_TIME -# include -# include -#else -# ifdef HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif /* TIME_WITH_SYS_TIME */ -#ifdef HAVE_UNISTD_H -# ifdef HAVE_SYS_TYPES_H -# include -# endif -# include -#endif -#ifdef HAVE_NETINET_IN_H -# include -#endif - -#include "shoot.h" - -#include "request.h" -#include "auth.h" -#include "header_f.h" -#include "helper.h" -#include "exit_code.h" -#include "transport.h" - -#ifndef DEFAULT_RETRYS -#define DEFAULT_RETRYS 5 -#endif - -#ifndef DEFAULT_TIMEOUT -#define DEFAULT_TIMEOUT 5000 -#endif - -char *usern; - -enum usteps usrlocstep; - -struct sipsak_regexp regexps; - -struct sipsak_sr_time timers; -struct sipsak_con_data cdata; -struct sipsak_counter counters; -struct sipsak_delay delays; - -/* if a reply was received successfully, return success, unless - * reply matching is enabled and no match occurred - */ - -static inline void on_success(char *rep) -{ - if ((rep != NULL) && re && regexec(re, rep, 0, 0, 0) == REG_NOMATCH) { - log_message(req); - fprintf(stderr, "error: RegExp failed\n"); - exit_code(32, __PRETTY_FUNCTION__, "regular expression failed"); - } else { - exit_code(0, __PRETTY_FUNCTION__, NULL); - } -} - -/* just print the given username and number into the first buffer and - * append an @ char */ -static inline void create_usern(char *target, char *username, int number) -{ - if (number >= 0) { - sprintf(target, "%s%i@", username, number); - } - else { - sprintf(target, "%s@", username); - } -} - -/* tries to take care of a redirection */ -void handle_3xx(struct sockaddr_in *tadr) -{ - char *uscheme, *uuser, *uhost, *contact; - - printf("** received redirect "); - if (warning_ext == 1) { - printf("from "); - warning_extract(rec); - printf("\n"); - } - else - printf("\n"); - /* we'll try to handle 301 and 302 here, other 3xx are to complex */ - regcomp(&(regexps.redexp), "^SIP/[0-9]\\.[0-9] 30[125] ", - REG_EXTENDED|REG_NOSUB|REG_ICASE); - if (regexec(&(regexps.redexp), rec, 0, 0, 0) == REG_NOERROR) { - /* try to find the contact in the redirect */ - contact = uri_from_contact(rec); - if (contact==NULL) { - fprintf(stderr, "error: cannot find Contact in this " - "redirect:\n%s\n", rec); - exit_code(3, __PRETTY_FUNCTION__, "missing Contact header in reply"); - } - /* correct our request */ - uri_replace(req, contact); - new_transaction(req, rep); - /* extract the needed information*/ - rport = 0; - address = 0; - parse_uri(contact, &uscheme, &uuser, &uhost, &rport); - if (!rport) - address = getsrvadr(uhost, &rport, &transport); - if (!address) - address = getaddress(uhost); - if (!address){ - fprintf(stderr, "error: cannot determine host " - "address from Contact of redirect:" - "\n%s\n", rec); - exit_code(2, __PRETTY_FUNCTION__, "missing host in Contact header"); - } - if (!rport) { - rport = 5060; - } - free(contact); - if (!outbound_proxy) - cdata.connected = set_target(tadr, address, rport, cdata.csock, cdata.connected); - } - else { - fprintf(stderr, "error: cannot handle this redirect:" - "\n%s\n", rec); - exit_code(2, __PRETTY_FUNCTION__, "unsupported redirect reply"); - } -} - -/* takes care of replies in the trace route mode */ -void trace_reply() -{ - char *contact; - - if (regexec(&(regexps.tmhexp), rec, 0, 0, 0) == REG_NOERROR) { - /* we received 483 to many hops */ - printf("%i: ", namebeg); - if (verbose > 2) { - printf("(%.3f ms)\n%s\n", - deltaT(&(timers.sendtime), &(timers.recvtime)), rec); - } - else { - warning_extract(rec); - printf("(%.3f ms) ", deltaT(&(timers.sendtime), &(timers.recvtime))); - print_message_line(rec); - } - namebeg++; - cseq_counter++; - create_msg(REQ_OPT, req, NULL, usern, cseq_counter); - set_maxforw(req, namebeg); - return; - } - else if (regexec(&(regexps.proexp), rec, 0, 0, 0) == REG_NOERROR) { - /* we received a provisional response */ - printf("%i: ", namebeg); - if (verbose > 2) { - printf("(%.3f ms)\n%s\n", - deltaT(&(timers.sendtime), &(timers.recvtime)), rec); - } - else { - warning_extract(rec); - printf("(%.3f ms) ", deltaT(&(timers.sendtime), &(timers.recvtime))); - print_message_line(rec); - } - delays.retryAfter = timer_t2; - cdata.dontsend=1; - return; - } - else { - /* anything else then 483 or provisional will - be treated as final */ - printf("%i: ", namebeg); - warning_extract(rec); - printf("(%.3f ms) ", deltaT(&(timers.sendtime), &(timers.recvtime))); - print_message_line(rec); - if ((contact = STRCASESTR(rec, CONT_STR)) != NULL || - (contact = STRCASESTR(rec, CONT_SHORT_STR)) != NULL) { - if (*contact == '\n') { - contact++; - } - printf("\t"); - print_message_line(contact); - } - else { - printf("\twithout Contact header\n"); - } - if (regexec(&(regexps.okexp), rec, 0, 0, 0) == REG_NOERROR) { - on_success(rec); - } else { - log_message(req); - exit_code(1, __PRETTY_FUNCTION__, "received final non-2xx reply"); - } - } -} - -/* takes care of replies in the default mode */ -void handle_default() -{ - /* in the normal send and reply case anything other - then 1xx will be treated as final response*/ - if (regexec(&(regexps.proexp), rec, 0, 0, 0) == REG_NOERROR) { - if (verbose > 1) { - printf("%s\n\n", rec); - printf("** reply received "); - if ((counters.send_counter == 1) || (STRNCASECMP(req, ACK_STR, ACK_STR_LEN) == 0)) { - printf("after %.3f ms **\n", deltaT(&(timers.firstsendt), &(timers.recvtime))); - } - else { - printf("%.3f ms after first send\n and " - "%.3f ms after last send **\n", deltaT(&(timers.firstsendt), &(timers.recvtime)), - deltaT(&(timers.sendtime), &(timers.recvtime))); - } - printf(" "); - print_message_line(rec); - printf(" provisional received; still" - " waiting for a final response\n"); - } - if (inv_trans) { - delays.retryAfter = timer_final; - } - else { - delays.retryAfter = timer_t2; - } - cdata.dontsend = 1; - return; - } - else { - if (verbose > 1) { - printf("%s\n\n", rec); - printf("** reply received "); - if ((counters.send_counter == 1) || (STRNCASECMP(req, ACK_STR, ACK_STR_LEN) == 0)){ - printf("after %.3f ms **\n", deltaT(&(timers.firstsendt), &(timers.recvtime))); - } - else { - printf("%.3f ms after first send\n and " - "%.3f ms after last send **\n", deltaT(&(timers.firstsendt), &(timers.recvtime)), - deltaT(&(timers.sendtime), &(timers.recvtime))); - } - printf(" "); - print_message_line(rec); - printf(" final received\n"); - } - else if (verbose>0) { - printf("%s\n", rec); - } - if (timing > 0) { - timing--; - if (timing == 0) { - if (counters.run == 0) { - counters.run++; - } - printf("%.3f/%.3f/%.3f ms\n", delays.small_delay, delays.all_delay / counters.run, delays.big_delay); - } - else { - counters.run++; - new_transaction(req, rep); - delays.retryAfter = timer_t1; - } - } - if (timing == 0) { - if (regexec(&(regexps.okexp), rec, 0, 0, 0) == REG_NOERROR) { - on_success(rec); - } - else { - log_message(req); - exit_code(1, __PRETTY_FUNCTION__, "received final non-2xx reply"); - } - } - } -} - -/* takes care of replies in the readntrash mode */ -void handle_randtrash() -{ - /* in randomzing trash we are expexting 4?? error codes - everything else should not be normal */ - if (regexec(&(regexps.errexp), rec, 0, 0, 0) == REG_NOERROR) { - if (verbose > 2) - printf("received:\n%s\n", rec); - if (verbose > 1) { - printf("received expected 4xx "); - if (warning_ext == 1) { - printf ("from "); - warning_extract(rec); - printf("\n"); - } - else { - printf("\n"); - } - } - } - else { - fprintf(stderr, "warning: did not received 4xx\n"); - if (verbose > 1) - printf("sended:\n%s\nreceived:\n%s\n", req, rec); - } - if (cseq_counter == nameend) { - if (counters.randretrys == 0) { - printf("random end reached. server survived :) respect!\n"); - exit_code(0, __PRETTY_FUNCTION__, NULL); - } - else { - printf("maximum sendings reached but did not " - "get a response on this request:\n%s\n", req); - log_message(req); - exit_code(3, __PRETTY_FUNCTION__, "missing reply on trashed request"); - } - } - else { - trash_random(req); - } -} - -/* takes care of replies in the usrloc mode */ -void handle_usrloc() -{ - char *crlf; - char ruri[11+12+20]; //FIXME: username length 20 should be dynamic - - if (regexec(&(regexps.proexp), rec, 0, 0, 0) == REG_NOERROR) { - if (verbose > 2) { - print_message_line(rec); - printf("ignoring provisional response\n\n"); - } - if (inv_trans) { - delays.retryAfter = timer_final; - } - else { - delays.retryAfter = timer_t2; - } - cdata.dontsend = 1; - } - else { - switch (usrlocstep) { - case REG_REP: - /* we have sent a register and look - at the response now */ - if (regexec(&(regexps.okexp), rec, 0, 0, 0) == REG_NOERROR) { - if (verbose > 1) { - printf ("\tOK\n"); - } - if (verbose > 2) { - printf("\n%s\n", rec); - } - } - else { - fprintf(stderr, "received:\n%s\nerror: didn't " - "received '200 OK' on register (see " - "above). aborting\n", rec); - log_message(req); - exit_code(1, __PRETTY_FUNCTION__, "received non-2xx reply for REGISTER"); - } - if (invite == 0 && message == 0) { - if (namebeg==nameend) { - if (verbose>0) { - printf("\nAll usrloc tests" - " completed successful.\nreceived" - " last message %.3f ms after first" - " request (test duration).\n", - deltaT(&(timers.firstsendt), &(timers.recvtime))); - } - if (delays.big_delay>0 && verbose>0) { - printf("biggest delay between " - "request and response was %.3f" - " ms\n", delays.big_delay); - } - if (counters.retrans_r_c>0 && verbose>0) { - printf("%i retransmission(s) received from server.\n", - counters.retrans_r_c); - } - if (counters.retrans_s_c>0 && verbose>0) { - printf("%i time(s) the timeout of " - "%i ms exceeded and request was" - " retransmitted.\n", - counters.retrans_s_c, delays.retryAfter); - if (counters.retrans_s_c > nagios_warn) { - log_message(req); - exit_code(4, __PRETTY_FUNCTION__, "#retransmissions above nagios warn level"); - } - } - if (timing) { - printf("%.3f ms\n", - deltaT(&(timers.firstsendt), &(timers.recvtime))); - } - on_success(rec); - } /* namebeg == nameend */ - /* lets see if we deceid to remove a - binding (case 6)*/ - if ( ((float)rand()/RAND_MAX)*100 > rand_rem) { - namebeg++; - cseq_counter++; - create_usern(usern, username, namebeg); - create_msg(REQ_REG, req, NULL, usern, cseq_counter); - } - else { - /* to prevent only removing of low - user numbers new random number*/ - cseq_counter++; - create_usern(usern, username, ((float)rand()/RAND_MAX) * namebeg); - create_msg(REQ_REM, req, NULL, usern, cseq_counter); - usrlocstep=UNREG_REP; - } - } /* invite == 0 && message == 0 */ - else if (invite == 1) { - cseq_counter++; - create_msg(REQ_INV, req, rep, usern, cseq_counter); - inv_trans = 1; - usrlocstep=INV_RECV; - } - else if (message == 1) { - cseq_counter++; - create_msg(REQ_MES, req, rep, usern, cseq_counter); - inv_trans = 0; - usrlocstep=MES_RECV; - } - break; - case INV_RECV: - /* see if we received our invite */ - sprintf(ruri, "%s sip:%s", INV_STR, usern); - if (!STRNCASECMP(rec, ruri, strlen(ruri))) { - if (verbose > 1) { - printf("\t\treceived invite\n"); - } - if (verbose > 2) { - printf("\n%s\n", rec); - } - cpy_vias(rec, rep); - cpy_rr(rec, rep, 0); - swap_ptr(&req, &rep); - usrlocstep=INV_OK_RECV; - inv_trans = 0; - } - else { - fprintf(stderr, "received:\n%s\nerror: did not " - "received the INVITE that was sent " - "(see above). aborting\n", rec); - log_message(req); - exit_code(1, __PRETTY_FUNCTION__, "did not received our own INVITE request"); - } - break; - case INV_OK_RECV: - /* did we received our ok ? */ - if (STRNCASECMP(rec, INV_STR, INV_STR_LEN)==0) { - if (verbose>0) { - printf("ignoring INVITE retransmission\n"); - } - counters.retrans_r_c++; - cdata.dontsend=1; - return; - } - if (regexec(&(regexps.okexp), rec, 0, 0, 0) == REG_NOERROR) { - if (verbose > 1) { - printf("\t200 OK received\n"); - } - if (verbose > 2) { - printf("\n%s\n", rec); - } - /* ACK was send already earlier generically */ - usrlocstep=INV_ACK_RECV; - cdata.dontsend=1; - } - else { - fprintf(stderr, "received:\n%s\nerror: did not " - "received the '200 OK' that was sent " - "as the reply on the INVITE (see " - "above). aborting\n", rec); - log_message(req); - exit_code(1, __PRETTY_FUNCTION__, "did not received our own 200 reply"); - } - break; - case INV_ACK_RECV: - /* did we received our ack */ - if (STRNCASECMP(rec, SIP200_STR, SIP200_STR_LEN)==0) { - if (verbose>0) { - printf("ignoring 200 OK retransmission\n"); - } - counters.retrans_r_c++; - cdata.dontsend=1; - return; - } - sprintf(ruri, "%s sip:sipsak_conf@", ACK_STR); - if (STRNCASECMP(rec, ruri, strlen(ruri))==0) { - if (verbose > 1) { - printf("\tACK received\n"); - } - if (verbose > 2) { - printf("\n%s\n", rec); - } - if (verbose>0 && nameend>0) { - printf("usrloc for %s%i completed " - "successful\n", username, namebeg); - } - else if (verbose>0) { - printf("usrloc for %s completed successful\n", username); - } - if (namebeg==nameend) { - if (verbose>0) { - printf("\nAll usrloc tests completed " - "successful.\nreceived last message" - " %.3f ms after first request (test" - " duration).\n", deltaT(&(timers.firstsendt), &(timers.recvtime))); - } - if (delays.big_delay>0) { - printf("biggest delay between " - "request and response was %.3f" - " ms\n", delays.big_delay); - } - if (counters.retrans_r_c>0) { - printf("%i retransmission(s) received from server.\n", - counters.retrans_r_c); - } - if (counters.retrans_s_c>0) { - printf("%i time(s) the timeout of " - "%i ms exceeded and request was" - " retransmitted.\n", - counters.retrans_s_c, delays.retryAfter); - if (counters.retrans_s_c > nagios_warn) { - log_message(req); - exit_code(4, __PRETTY_FUNCTION__, "#retransmissions above nagios warn level"); - } - } - on_success(rec); - } /* namebeg == nameend */ - if (usrloc == 1) { - /* lets see if we deceid to remove a - binding (case 6)*/ - if (((float)rand()/RAND_MAX) * 100 > rand_rem) { - namebeg++; - cseq_counter++; - create_usern(usern, username, namebeg); - create_msg(REQ_REG, req, NULL, usern, cseq_counter); - usrlocstep=REG_REP; - } - else { - /* to prevent only removing of low - user numbers new random number*/ - cseq_counter++; - create_usern(usern, username, ((float)rand()/RAND_MAX) * namebeg); - create_msg(REQ_REM, req, NULL, usern, cseq_counter); - usrlocstep=UNREG_REP; - } - } /* usrloc == 1 */ - else { - namebeg++; - cseq_counter++; - create_usern(usern, username, namebeg); - create_msg(REQ_INV, req, rep, usern, cseq_counter); - inv_trans = 1; - usrlocstep=INV_RECV; - } - } /* STRNCASECMP */ - else { - fprintf(stderr, "received:\n%s\nerror: did not " - "received the 'ACK' that was sent " - "as the reply on the '200 OK' (see " - "above). aborting\n", rec); - log_message(req); - exit_code(1, __PRETTY_FUNCTION__, "missing ACK that was send by myself"); - } - break; - case MES_RECV: - /* we sent the message and look if its - forwarded to us */ - sprintf(ruri, "%s sip:%s", MES_STR, usern); - if (!STRNCASECMP(rec, ruri, strlen(ruri))) { - if (verbose > 1) { - crlf=STRCASESTR(rec, "\r\n\r\n"); - crlf=crlf+4; - printf(" received message\n '%s'\n", crlf); - } - if (verbose > 2) { - printf("\n%s\n", rec); - } - cpy_vias(rec, rep); - swap_ptr(&req, &rep); - usrlocstep=MES_OK_RECV; - } - else { - fprintf(stderr, "received:\n%s\nerror: did not " - "received the 'MESSAGE' that was sent " - "(see above). aborting\n", rec); - log_message(req); - exit_code(1, __PRETTY_FUNCTION__, "did not received my own MESSAGE request"); - } - break; - case MES_OK_RECV: - /* we sent our reply on the message and - look if this is also forwarded to us */ - if (STRNCASECMP(rec, MES_STR, MES_STR_LEN)==0) { - if (verbose>0) { - printf("ignoring MESSAGE retransmission\n"); - } - counters.retrans_r_c++; - cdata.dontsend=1; - return; - } - if (regexec(&(regexps.okexp), rec, 0, 0, 0) == REG_NOERROR) { - if (verbose > 1) { - printf(" reply received\n\n"); - } - else if (verbose>0 && nameend>0) { - printf("usrloc for %s%i completed " - "successful\n", username, namebeg); - } - else if (verbose>0) { - printf("usrloc for %s completed successful\n", username); - } - if (namebeg==nameend) { - if (verbose>0) { - printf("\nAll usrloc tests completed " - "successful.\nreceived last message" - " %.3f ms after first request (test" - " duration).\n", deltaT(&(timers.firstsendt), &(timers.recvtime))); - } - if (delays.big_delay>0) { - printf("biggest delay between " - "request and response was %.3f" - " ms\n", delays.big_delay); - } - if (counters.retrans_r_c>0) { - printf("%i retransmission(s) " - "received from server.\n", - counters.retrans_r_c); - } - if (counters.retrans_s_c>0) { - printf("%i time(s) the timeout of " - "%i ms exceeded and request was" - " retransmitted.\n", - counters.retrans_s_c, delays.retryAfter); - if (counters.retrans_s_c > nagios_warn) { - log_message(req); - exit_code(4, __PRETTY_FUNCTION__, "#retransmissions above nagios warn level"); - } - } - on_success(rec); - } /* namebeg == nameend */ - if (usrloc == 1) { - /* lets see if we deceid to remove a - binding (case 6)*/ - if (((float)rand()/RAND_MAX) * 100 > rand_rem) { - namebeg++; - cseq_counter++; - create_usern(usern, username, namebeg); - create_msg(REQ_REG, req, NULL, usern, cseq_counter); - usrlocstep=REG_REP; - } - else { - /* to prevent only removing of low - user numbers new random number*/ - cseq_counter++; - create_usern(usern, username, ((float)rand()/RAND_MAX) * namebeg); - create_msg(REQ_REM, req, NULL, usern, cseq_counter); - usrlocstep=UNREG_REP; - } - } /* usrloc == 1 */ - else { - namebeg++; - cseq_counter++; - create_usern(usern, username, namebeg); - create_msg(REQ_MES, req, NULL, usern, cseq_counter); - usrlocstep=MES_RECV; - } - } /* regexec */ - else { - if (verbose>0) { - if (mes_body) { - fprintf(stderr, "received:\n%s\nerror: did" - " not received 200 for the " - "MESSAGE (see above)\n", - rec); - } - else { - fprintf(stderr, "received:\n%s\nerror: did" - " not received the '200 OK' " - "that was sent as the reply on" - " the MESSAGE (see above). " - "aborting\n", rec); - } - } - log_message(req); - exit_code(1, __PRETTY_FUNCTION__, "received non-2xx reply for MESSAGE request"); - } - break; - case UNREG_REP: - if (STRNCASECMP(rec, MES_STR, MES_STR_LEN)==0) { - if (verbose>0) { - printf("ignoring MESSAGE retransmission\n"); - } - counters.retrans_r_c++; - cdata.dontsend=1; - return; - } - if (regexec(&(regexps.okexp), rec, 0, 0, 0) == REG_NOERROR) { - if (verbose > 1) { - printf(" OK\n\n"); - } - else if (verbose>0 && nameend>0) { - printf("Binding removal for %s%i " - "successful\n", username, namebeg); - } - else if (verbose>0) { - printf("Binding removal for %s successful\n", username); - } - namebeg++; - cseq_counter++; - create_usern(usern, username, namebeg); - create_msg(REQ_REG, req, NULL, usern, cseq_counter); - usrlocstep=REG_REP; - } - else { - fprintf(stderr, "received:\n%s\nerror: did not " - "received the expected 200 on the " - "remove bindings request for %s%i (see" - " above). aborting\n", rec, username, - namebeg); - log_message(req); - exit_code(1, __PRETTY_FUNCTION__, "received non-2xx reply for de-register request"); - } - break; - default: - fprintf(stderr, "error: unknown step in usrloc\n"); - exit_code(2, __PRETTY_FUNCTION__, "unknown step in usrloc"); - break; - } /* switch */ - } /* regexec proexp */ -} - -void before_sending() -{ - /* some initial output */ - if ((usrloc == 1||invite == 1||message == 1) && (verbose > 1) && (cdata.dontsend == 0)) { - switch (usrlocstep) { - case REG_REP: - if (nameend>0) - printf("registering user %s%i... ", username, namebeg); - else - printf("registering user %s... ", username); - break; - case INV_RECV: - if (nameend>0) - printf("inviting user %s%i... ", username, namebeg); - else - printf("inviting user %s... ", username); - break; - case INV_OK_RECV: - printf("sending invite reply... "); - break; - case INV_ACK_RECV: - printf("sending invite ack... "); - break; - case MES_RECV: - if (nameend>0) - printf("sending message to %s%i... ", username, namebeg); - else - printf("sending message to %s... ", username); - break; - case MES_OK_RECV: - if (mes_body) - printf("sending message ... \n"); - else - printf("sending message reply... "); - break; - case UNREG_REP: - if (nameend>0) - printf("remove binding for %s%i...", username, namebeg); - else - printf("remove binding for %s...", username); - break; - } - } /* if usrloc...*/ - else if (flood == 1 && verbose > 0) { - printf("flooding message number %i\n", namebeg); - } - else if (randtrash == 1 && verbose > 0) { - printf("message with %i randomized chars\n", cseq_counter); - if (verbose > 2) - printf("request:\n%s\n", req); - } -} - -/* this is the main function with the loops and modes */ -void shoot(char *buf, int buff_size) -{ - struct timespec sleep_ms_s, sleep_rem; - int ret, cseqtmp, rand_tmp; - char buf2[BUFSIZE], buf3[BUFSIZE], lport_str[LPORT_STR_LEN]; - - /* delays.retryAfter = DEFAULT_TIMEOUT; */ - if (transport == SIP_UDP_TRANSPORT) { - delays.retryAfter = timer_t1; - } - else { - delays.retryAfter = timer_final; - } - inv_trans = 0; - cseq_counter = 1; - usrlocstep = REG_REP; - - /* initalize local vars */ - cdata.dontsend=cdata.dontrecv=counters.retrans_r_c=counters.retrans_s_c= 0; - delays.big_delay=counters.send_counter=counters.run= 0; - timers.delaytime.tv_sec = 0; - timers.delaytime.tv_usec = 0; - usern = NULL; - /* initialize local arrays */ - memset(buf2, 0, BUFSIZE); - memset(buf3, 0, BUFSIZE); - memset(lport_str, 0, LPORT_STR_LEN); - - cdata.csock = cdata.usock = -1; - cdata.connected = 0; - cdata.buf_tmp = NULL; - cdata.buf_tmp_size = 0; - - memset(&(timers.sendtime), 0, sizeof(timers.sendtime)); - memset(&(timers.recvtime), 0, sizeof(timers.recvtime)); - memset(&(timers.firstsendt), 0, sizeof(timers.firstsendt)); - memset(&(timers.starttime), 0, sizeof(timers.starttime)); - memset(&(timers.delaytime), 0, sizeof(timers.delaytime)); - - req = buf; - rep = buf2; - rec = buf3; - - create_sockets(&cdata); - - if (sleep_ms != 0) { - if (sleep_ms == -2) { - rand_tmp = rand(); - sleep_ms_s.tv_sec = rand_tmp / 1000; - sleep_ms_s.tv_nsec = (rand_tmp % 1000) * 1000000; - } - else { - sleep_ms_s.tv_sec = sleep_ms / 1000; - sleep_ms_s.tv_nsec = (sleep_ms % 1000) * 1000000; - } - } - - if (replace_b == 1){ - replace_string(req, "$dsthost$", domainname); - replace_string(req, "$srchost$", fqdn); - sprintf(lport_str, "%i", lport); - replace_string(req, "$port$", lport_str); - if (username) - replace_string(req, "$user$", username); - } - if (replace_str) - replace_strings(req, replace_str); - - /* set all regular expression to simplfy the result code identification */ - regcomp(&(regexps.replyexp), "^SIP/[0-9]\\.[0-9] [1-6][0-9][0-9]", - REG_EXTENDED|REG_NOSUB|REG_ICASE); - regcomp(&(regexps.proexp), "^SIP/[0-9]\\.[0-9] 1[0-9][0-9] ", - REG_EXTENDED|REG_NOSUB|REG_ICASE); - regcomp(&(regexps.okexp), "^SIP/[0-9]\\.[0-9] 2[0-9][0-9] ", - REG_EXTENDED|REG_NOSUB|REG_ICASE); - regcomp(&(regexps.redexp), "^SIP/[0-9]\\.[0-9] 3[0-9][0-9] ", - REG_EXTENDED|REG_NOSUB|REG_ICASE); - regcomp(&(regexps.authexp), "^SIP/[0-9]\\.[0-9] 40[17] ", - REG_EXTENDED|REG_NOSUB|REG_ICASE); - regcomp(&(regexps.errexp), "^SIP/[0-9]\\.[0-9] 4[0-9][0-9] ", - REG_EXTENDED|REG_NOSUB|REG_ICASE); - regcomp(&(regexps.tmhexp), "^SIP/[0-9]\\.[0-9] 483 ", - REG_EXTENDED|REG_NOSUB|REG_ICASE); - - if (username) { - if (nameend > 0) { - usern = str_alloc(strlen(username) + 12); - create_usern(usern, username, namebeg); - } - else { - if (*(username + strlen(username) - 1) != '@') { - usern = str_alloc(strlen(username) + 2); - create_usern(usern, username, -1); - } - else { - usern = username; - } - } - } - - if (usrloc == 1||invite == 1||message == 1){ - /* calculate the number of required steps and create initial mes */ - if (usrloc == 1) { - create_msg(REQ_REG, req, NULL, usern, cseq_counter); - usrlocstep=REG_REP; - } - else if (invite == 1) { - create_msg(REQ_INV, req, rep, usern, cseq_counter); - inv_trans = 1; - usrlocstep=INV_RECV; - } - else { - create_msg(REQ_MES, req, rep, usern, cseq_counter); - if (mes_body) - usrlocstep=MES_OK_RECV; - else - usrlocstep=MES_RECV; - } - } - else if (trace == 1){ - /* for trace we need some spezial initis */ - namebeg=0; - create_msg(REQ_OPT, req, NULL, usern, cseq_counter); - set_maxforw(req, namebeg); - } - else if (flood == 1){ - if (nameend<=0) nameend=INT_MAX; - namebeg=1; - create_msg(REQ_FLOOD, req, NULL, usern, cseq_counter); - } - else if (randtrash == 1){ - counters.randretrys=0; - namebeg=1; - create_msg(REQ_RAND, req, NULL, usern, cseq_counter); - nameend=(int)strlen(req); - if (trashchar == 1){ - if (trashchar < nameend) - nameend=trashchar; - else - fprintf(stderr, "warning: number of trashed chars to big. setting to " - "request length\n"); - } - trash_random(req); - } - else { - /* for none of the modes we also need some inits */ - if (file_b == 0) { - namebeg=1; - create_msg(REQ_OPT, req, NULL, usern, cseq_counter); - } - else { - if (STRNCASECMP(req, INV_STR, INV_STR_LEN) == 0) { - inv_trans = 1; - } - if(via_ins == 1) - add_via(req); - } - /* delays.retryAfter = delays.retryAfter / 10; */ - if(maxforw!=-1) - set_maxforw(req, maxforw); - } - - cdata.connected = set_target(&(cdata.adr), address, rport, cdata.csock, cdata.connected); - - /* here we go until someone decides to exit */ - while(1) { - before_sending(); - - if (sleep_ms == -2) { - rand_tmp = rand(); - sleep_ms_s.tv_sec = rand_tmp / 1000; - sleep_ms_s.tv_nsec = (rand_tmp % 1000) * 1000; - } - if (sleep_ms != 0) { - dbg("sleeping for %li s + %li ns\n", sleep_ms_s.tv_sec, sleep_ms_s.tv_nsec); - nanosleep(&sleep_ms_s, &sleep_rem); - } - - send_message(req, &cdata, &counters, &timers); - - /* in flood we are only interested in sending so skip the rest */ - if (flood == 0) { - ret = recv_message(rec, BUFSIZE, inv_trans, &delays, &timers, - &counters, &cdata, ®exps); - if(ret > 0) - { - if (usrlocstep == INV_OK_RECV) { - swap_ptr(&rep, &req); - } - /* send ACK for non-provisional reply on INVITE */ - if ((STRNCASECMP(req, "INVITE", 6)==0) && - (regexec(&(regexps.replyexp), rec, 0, 0, 0) == REG_NOERROR) && - (regexec(&(regexps.proexp), rec, 0, 0, 0) == REG_NOMATCH)) { - build_ack(req, rec, rep, ®exps); - cdata.dontsend = 0; - inv_trans = 0; - /* lets fire the ACK to the server */ - send_message(rep, &cdata, &counters, &timers); - inv_trans = 1; - } - /* check for old CSeq => ignore retransmission */ - cseqtmp = cseq(rec); - if ((0 < cseqtmp) && (cseqtmp < cseq_counter)) { - if (verbose>0) { - printf("ignoring retransmission\n"); - } - counters.retrans_r_c++; - cdata.dontsend = 1; - continue; - } - else if (regexec(&(regexps.authexp), rec, 0, 0, 0) == REG_NOERROR) { - if (!username && !auth_username) { - if (timing > 0) { - timing--; - if (timing == 0) { - if (counters.run == 0) { - counters.run++; - } - printf("%.3f/%.3f/%.3f ms\n", delays.small_delay, delays.all_delay / counters.run, delays.big_delay); - exit_code(0, __PRETTY_FUNCTION__, NULL); - } - counters.run++; - new_transaction(req, rep); - delays.retryAfter = timer_t1; - continue; - } - fprintf(stderr, "%s\nerror: received 40[17] but cannot " - "authentication without a username or auth username\n", rec); - log_message(req); - exit_code(2, __PRETTY_FUNCTION__, "missing username for authentication"); - } - /* prevents a strange error */ - regcomp(&(regexps.authexp), "^SIP/[0-9]\\.[0-9] 40[17] ", REG_EXTENDED|REG_NOSUB|REG_ICASE); - insert_auth(req, rec); - if (verbose > 2) - printf("\nreceived:\n%s\n", rec); - new_transaction(req, rep); - continue; - } /* if auth...*/ - /* lets see if received a redirect */ - if (redirects == 1 && regexec(&(regexps.redexp), rec, 0, 0, 0) == REG_NOERROR) { - handle_3xx(&(cdata.adr)); - } /* if redircts... */ - else if (trace == 1) { - trace_reply(); - } /* if trace ... */ - else if (usrloc == 1||invite == 1||message == 1) { - handle_usrloc(); - } - else if (randtrash == 1) { - handle_randtrash(); - } - else { - handle_default(); - } /* redirect, auth, and modes */ - } /* ret > 0 */ - else if (ret == -1) { // we did not got anything back, send again - /* no re-transmission on reliable transports */ - if (transport != SIP_UDP_TRANSPORT) { - cdata.dontsend = 1; - } - continue; - } - else if (ret == -2) { // we received non-matching ICMP - cdata.dontsend = 1; - continue; - } - else { - if (usrloc == 1) { - printf("failed\n"); - } - perror("socket error"); - exit_code(3, __PRETTY_FUNCTION__, "internal socket error"); - } - } /* !flood */ - else { - if (counters.send_counter == 1) { - memcpy(&(timers.firstsendt), &(timers.sendtime), sizeof(struct timeval)); - } - if (namebeg==nameend) { - printf("flood end reached\n"); - printf("it took %.3f ms seconds to send %i request.\n", - deltaT(&(timers.firstsendt), &(timers.sendtime)), namebeg); - printf("we sent %f requests per second.\n", - (namebeg/(deltaT(&(timers.firstsendt), &(timers.sendtime)))*1000)); - exit_code(0, __PRETTY_FUNCTION__, NULL); - } - namebeg++; - cseq_counter++; - create_msg(REQ_FLOOD, req, NULL, usern, cseq_counter); - } - } /* while 1 */ - - /* this should never happen any more... */ - if (randtrash == 1) { - exit_code(0, __PRETTY_FUNCTION__, NULL); - } - printf("** give up retransmissioning....\n"); - if (counters.retrans_r_c>0 && (verbose > 1)) { - printf("%i retransmissions received during test\n", counters.retrans_r_c); - } - if (counters.retrans_s_c>0 && (verbose > 1)) { - printf("sent %i retransmissions during test\n", counters.retrans_s_c); - } - exit_code(3, __PRETTY_FUNCTION__, "got outside of endless messaging loop"); -} diff -Nru sipsak-0.9.6+git20170713/shoot.h sipsak-0.9.7/shoot.h --- sipsak-0.9.6+git20170713/shoot.h 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/shoot.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2002-2004 Fhg Fokus - * Copyright (C) 2004-2005 Nils Ohlmeier - * - * This file belongs to sipsak, a free sip testing tool. - * - * sipsak is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * sipsak is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef SIPSAK_SHOOT_H -#define SIPSAK_SHOOT_H - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#define LPORT_STR_LEN 6 - -struct sipsak_regexp { - regex_t redexp; - regex_t proexp; - regex_t okexp; - regex_t tmhexp; - regex_t errexp; - regex_t authexp; - regex_t replyexp; -}; - -enum usteps { - REG_REP, - INV_RECV, - INV_OK_RECV, - INV_ACK_RECV, - MES_RECV, - MES_OK_RECV, - UNREG_REP -}; - -int inv_trans; - -void shoot(char *buff, int buff_size); - -#endif diff -Nru sipsak-0.9.6+git20170713/sipsak.c sipsak-0.9.7/sipsak.c --- sipsak-0.9.6+git20170713/sipsak.c 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/sipsak.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1103 +0,0 @@ -/* - * Copyright (C) 2002-2004 Fhg Fokus - * Copyright (C) 2004-2005 Nils Ohlmeier - * - * This file belongs to sipsak, a free sip testing tool. - * - * sipsak is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * sipsak is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/* sipsak written by nils ohlmeier (ohlmeier@fokus.fraunhofer.de). - based up on a modifyed version of shoot. - return codes are now: 0 for an received 200, 1 for all other - received responses, 2 for local errors, and 3 for remote errors. -*/ - -/* changes by jiri@iptel.org; now messages can be really received; - status code returned is 2 for some local errors , 0 for success - and 1 for remote error -- ICMP/timeout; can be used to test if - a server is alive; 1xx messages are now ignored; windows support - dropped -*/ - -#include "sipsak.h" - -#ifdef HAVE_UNISTD_H -# ifdef HAVE_SYS_TYPES_H -# include -# endif -# include -#endif -#ifdef TIME_WITH_SYS_TIME -# include -# include -#else -# ifdef HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif -#ifdef HAVE_SYS_WAIT_H -# include -#endif -#ifdef HAVE_GETOPT_H -# include -#endif -#ifdef HAVE_SYSLOG_H -# include -#endif - -#include "helper.h" -#include "header_f.h" -#include "shoot.h" -#include "exit_code.h" - -static void sigchld_handler(int signo) -{ - int chld_status; - pid_t chld; - - while ((chld = waitpid(-1, &chld_status, WNOHANG)) > 0); -} - - -void print_version() { - printf("%s %s by Nils Ohlmeier\n", PACKAGE_NAME, PACKAGE_VERSION); - printf(" Copyright (C) 2002-2004 FhG Fokus\n"); - printf(" Copyright (C) 2004-2005 Nils Ohlmeier\n"); - printf(" report bugs to %s\n\n", PACKAGE_BUGREPORT); - printf( - " shoot : sipsak [-f FILE] [-L] -s SIPURI\n" - " trace : sipsak -T -s SIPURI\n" - " usrloc : sipsak -U [-I|M] [-b NUMBER] [-e NUMBER] [-x NUMBER] [-z NUMBER] -s SIPURI\n" - " usrloc : sipsak -I|M [-b NUMBER] [-e NUMBER] -s SIPURI\n" - " usrloc : sipsak -U [-C SIPURI] [-x NUMBER] -s SIPURI\n" - " message: sipsak -M [-B STRING] [-O STRING] [-c SIPURI] -s SIPURI\n" - " flood : sipsak -F [-e NUMBER] -s SIPURI\n" - " random : sipsak -R [-t NUMBER] -s SIPURI\n\n" - " additional parameter in every mode:\n" - ); - printf(" [-a PASSWORD] [-d] [-i] [-H HOSTNAME] [-l PORT] [-m NUMBER] [-n] " - "[-N]\n" - " [-r PORT] [-v] [-V] [-w]\n\n" - ); -} - -#ifdef HAVE_GETOPT_LONG -void print_long_help() { - print_version(); - printf( - " --help displays this help message\n" - " --version prints version string only\n" - " --filename=FILE the file which contains the SIP message to send\n" - " use - for standard input\n" - " --no-crlf de-activate CR (\\r) insertion\n" - " --sip-uri=SIPURI the destination server uri in form\n" - " sip:[user@]servername[:port]\n" - " --traceroute activates the traceroute mode\n" - ); - printf(" --usrloc-mode activates the usrloc mode\n" - " --invite-mode simulates a successful calls with itself\n" - " --message-mode sends messages to itself\n" - " --contact=SIPURI use the given uri as Contact in REGISTER\n" - " --appendix-begin=NUMBER the starting number appendix to the user name (default: 0)\n" - " --appendix-end=NUMBER the ending numer of the appendix to the user name\n" - " --sleep=NUMBER sleep number ms before sending next request\n" - ); - printf(" --expires=NUMBER the expires header field value (default: 15)\n" - " --remove-bindings=NUMBER activates randomly removing of user bindings\n" - " --flood-mode activates the flood mode\n" - " --random-mode activates the random modues (dangerous)\n" - " --trash-chars=NUMBER the maximum number of trashed character in random mode\n" - " (default: request length)\n" - ); - printf(" --local-port=PORT the local port to use (default: any)\n" - " --remote-port=PORT the remote port to use (default: 5060)\n" - " --outbound-proxy=HOSTNAME request target (outbound proxy)\n" - " --hostname=HOSTNAME overwrites the local hostname in all headers\n" - " --max-forwards=NUMBER the value for the max-forwards header field\n" -#ifdef OLDSTYLE_FQDN - " --numeric use IP instead of FQDN in the Via-Line\n" -#else - " --numeric use FQDN instead of IP in the Via-Line\n" -#endif -); - printf(" --processes=NUMBER Divide the workflow among the number of processes\n" - " --auth-username=STRING username for authentication\n" - ); - printf(" --no-via deactivate the insertion of a Via-Line\n" - " --password=PASSWORD password for authentication\n" - " (if omitted password=username)\n" - " --ignore-redirects ignore redirects\n" - " --verbose each v produces more verbosity (max. 3)\n" - " --extract-ip extract IP from the warning in reply\n" - " --replace-string=STRING replacement for a special mark in the message\n" - " --replace activates replacement of variables\n" - ); - printf(" --nagios-code returns exit codes Nagios compliant\n" - " --nagios-warn=NUMBER return Nagios warning if retrans > number\n" - " --message-body=STRING send a message with string as body\n" - " --disposition=STRING Content-Disposition value\n" - " --search=REGEXP search for a RegExp in replies and return error\n" - " on failfure\n" - " --timing=NUMBER number of test runs and print just the timings\n" - " --symmetric send and received on the same port\n" - " --from=SIPURI use the given uri as From in MESSAGE\n" - " --timeout-factor=NUMBER timeout multiplier for INVITE transactions\n" - " on non-reliable transports (default: 64)\n" - " --timer-t1=NUMBER timeout T1 in ms (default: %i)\n" - " --transport=STRING specify transport to be used\n" - " --headers=STRING adds additional headers to the request\n" - " --local-ip=STRING specify local ip address to be used\n" - " --authhash=STRING ha1 hash for authentication instead of password\n" - " --sylog=NUMBER log exit message to syslog with given log level\n" - , DEFAULT_TIMEOUT - ); -#ifdef WITH_TLS_TRANSP - printf(" --tls-ca-cert=FILE file with the cert of the root CA\n" - " --tls-client-cert=FILE file with the cert which sipsak will send\n" - " --tls-ignore-cert-failure ignore failures during the TLS handshake\n" - ); -#endif - exit_code(0, __PRETTY_FUNCTION__, NULL); -} -#endif - -/* prints out some usage help and exits */ -void print_help() { - print_version(); - printf( - " -h displays this help message\n" - " -V prints version string only\n" - " -f FILE the file which contains the SIP message to send\n" - " use - for standard input\n" - " -L de-activate CR (\\r) insertion in files\n" - " -s SIPURI the destination server uri in form\n" - " sip:[user@]servername[:port]\n" - " -T activates the traceroute mode\n" - " -U activates the usrloc mode\n" - " -I simulates a successful calls with itself\n" - " -M sends messages to itself\n" - ); - printf( - " -C SIPURI use the given uri as Contact in REGISTER\n" - " -b NUMBER the starting number appendix to the user name (default: 0)\n" - " -e NUMBER the ending numer of the appendix to the user name\n" - " -o NUMBER sleep number ms before sending next request\n" - " -x NUMBER the expires header field value (default: 15)\n" - " -z NUMBER activates randomly removing of user bindings\n" - " -F activates the flood mode\n" - ); - printf( - " -R activates the random modues (dangerous)\n" - " -t NUMBER the maximum number of trashed character in random mode\n" - " (default: request length)\n" - " -l PORT the local port to use (default: any)\n" - " -r PORT the remote port to use (default: 5060)\n" - " -p HOSTNAME request target (outbound proxy)\n" - ); - printf( - " -H HOSTNAME overwrites the local hostname in all headers\n" - " -m NUMBER the value for the max-forwards header field\n" -#ifdef OLDSTYLE_FQDN - " -n use IP instead of FQDN in the Via-Line\n" -#else - " -n use FQDN instead of IP in the Via-Line\n" -#endif - " -i deactivate the insertion of a Via-Line\n" - " -a PASSWORD password for authentication\n" - " (if omitted password=\"\")\n" - " -u STRING Authentication username\n" - ); - printf( - " -d ignore redirects\n" - " -v each v produces more verbosity (max. 3)\n" - " -w extract IP from the warning in reply\n" - " -g STRING replacement for a special mark in the message\n" - " -G activates replacement of variables\n" - " -N returns exit codes Nagios compliant\n" - " -q STRING search for a RegExp in replies and return error\n" - " on failure\n"); - printf(" -W NUMBER return Nagios warning if retrans > number\n" - " -B STRING send a message with string as body\n" - " -O STRING Content-Disposition value\n" - " -P NUMBER Number of processes to start\n" - " -A NUMBER number of test runs and print just timings\n" - " -S use same port for receiving and sending\n" - " -c SIPURI use the given uri as From in MESSAGE\n" - " -D NUMBER timeout multiplier for INVITE transactions\n" - " on non-reliable transports (default: 64)\n" - " -Z NUMBER timeout T1 in ms (default: %i)\n" - " -E STRING specify transport to be used\n" - " -j STRING adds additional headers to the request\n" - " -J STRING ha1 hash for authentication instead of password\n" - " -k STRING specify local ip address to be used\n" - " -K NUMBER log exit message to syslog with given log level\n" - , DEFAULT_TIMEOUT - ); - exit_code(0, __PRETTY_FUNCTION__, NULL); -} - -int main(int argc, char *argv[]) -{ - FILE *pf; - char buff[BUFSIZE]; - int c, i, port; - unsigned int tsp; - char *scheme, *user, *host, *backup; - pid_t pid; - struct timespec ts; - int upp; - -#ifdef HAVE_GETOPT_LONG - int option_index = 0; - static struct option l_opts[] = { - {"help", 0, 0, 0}, - {"version", 0, 0, 'V'}, - {"filename", 1, 0, 'f'}, - {"sip-uri", 1, 0, 's'}, - {"traceroute-mode", 0, 0, 'T'}, - {"usrloc-mode", 0, 0, 'U'}, - {"invite-mode", 0, 0, 'I'}, - {"message-mode", 0, 0, 'M'}, - {"contact", 1, 0, 'C'}, - {"appendix-begin", 1, 0, 'b'}, - {"appendix-end", 1, 0, 'e'}, - {"sleep", 1, 0, 'o'}, - {"expires", 1, 0, 'x'}, - {"remove-bindings", 1, 0, 'z'}, - {"flood-mode", 0, 0, 'F'}, - {"random-mode", 0, 0, 'R'}, - {"trash-chars", 1, 0, 't'}, - {"local-port", 1, 0, 'l'}, - {"remote-port", 1, 0, 'r'}, - {"outbound-proxy", 1, 0, 'p'}, - {"hostname", 1, 0, 'H'}, - {"max-fowards", 1, 0, 'm'}, - {"numeric", 0, 0, 'n'}, - {"no-via", 0, 0, 'i'}, - {"password", 1, 0, 'a'}, - {"ignore-redirects", 0, 0, 'd'}, - {"verbose", 0, 0, 'v'}, - {"extract-ip", 0, 0, 'w'}, - {"replace-string", 0, 0, 'g'}, - {"replace", 0, 0, 'G'}, - {"nagios-code", 0, 0, 'N'}, - {"nagios-warn", 1, 0, 'W'}, - {"search", 1, 0, 'q'}, - {"message-body", 1, 0, 'B'}, - {"disposition", 1, 0, 'O'}, - {"processes", 1, 0, 'P'}, - {"auth-username", 1, 0, 'u'}, - {"no-crlf", 0, 0, 'L'}, - {"timing", 1, 0, 'A'}, - {"symmetric", 0, 0, 'S'}, - {"from", 1, 0, 'c'}, - {"timeout-factor", 1, 0, 'D'}, - {"timer-t1", 1, 0, 'Z'}, - {"transport", 1, 0, 'E'}, - {"headers", 1, 0, 'j'}, - {"authhash", 1, 0, 'J'}, - {"local-ip", 1, 0, 'k'}, - {"syslog", 1, 0, 'K'}, -#ifdef WITH_TLS_TRANSP - {"tls-ca-cert", 1, 0, 0}, - {"tls-client-cert", 1, 0, 0}, - {"tls-ignore-cert-failure", 0, 0, 0}, -#endif - {0, 0, 0, 0} - }; -#endif - /* some initialisation to be safe */ - file_b=uri_b=trace=lport=usrloc=flood=verbose=randtrash=trashchar = 0; - warning_ext=rand_rem=nonce_count=replace_b=invite=message=sysl = 0; - sleep_ms=empty_contact=nagios_warn=timing=outbound_proxy=symmetric = 0; - namebeg=nameend=maxforw= -1; -#ifdef OLDSTYLE_FQDN - numeric = 0; -#else - numeric = 1; -#endif - via_ins=redirects=fix_crlf=processes = 1; - username=password=replace_str=hostname=contact_uri=mes_body = NULL; - con_dis=auth_username=from_uri=headers=authhash=local_ip = NULL; - scheme = user = host = backup = req = rep = rec = NULL; - re = NULL; - address= 0; - transport=tsp = 0; - rport = port = 0; - expires_t = USRLOC_EXP_DEF; - timer_t1 = SIP_T1; - timer_t2 = 8; - timer_final = 64; - memset(buff, 0, BUFSIZE); - memset(fqdn, 0, FQDN_SIZE); -#ifdef WITH_TLS_TRANSP - cert_file = ca_file = NULL; - ignore_ca_fail = 0; -# ifdef USE_GNUTLS - tls_session = NULL; - xcred = NULL; -# else -# ifdef USE_OPENSSL - ctx = NULL; - ssl = NULL; -# endif -#endif -#endif /* WITH_TLS_TRANSP */ - - if (argc==1) { - print_help(); - } - - /* lots of command line switches to handle*/ -#ifdef HAVE_GETOPT_LONG - while ((c=getopt_long(argc, argv, "a:A:b:B:c:C:dD:e:E:f:Fg:GhH:iIj:J:k:K:l:Lm:MnNo:O:p:P:q:r:Rs:St:Tu:UvVwW:x:z:Z:", l_opts, &option_index)) != EOF){ -#else - while ((c=getopt(argc, argv, "a:A:b:B:c:C:dD:e:E:f:Fg:GhH:iIj:J:k:K:l:Lm:MnNo:O:p:P:q:r:Rs:St:Tu:UvVwW:x:z:Z:")) != EOF){ -#endif - switch(c){ -#ifdef HAVE_GETOPT_LONG - case 0: - printf("long option %s", l_opts[option_index].name); - if (optarg) { - printf(" with arg %s", optarg); - } - printf("\n"); - if (STRNCASECMP("help", l_opts[option_index].name, 4) == 0) { - print_long_help(); - } -#ifdef WITH_TLS_TRANSP - else if (STRNCASECMP("tls-ca-cert", l_opts[option_index].name, 11) == 0) { - pf = fopen(optarg, "rb"); - if (!pf){ - fprintf(stderr, "error: unable to open the CA cert file '%s'.\n", optarg); - exit_code(2, __PRETTY_FUNCTION__, "failed to open CA cert file"); - } - fclose(pf); - ca_file=optarg; - break; - } - else if (STRNCASECMP("tls-ignore-cert-failure", l_opts[option_index].name, 22) == 0) { - ignore_ca_fail = 1; - break; - } - else if (STRNCASECMP("tls-client-cert", l_opts[option_index].name, 14) == 0) { - pf = fopen(optarg, "rb"); - if (!pf){ - fprintf(stderr, "error: unable to open the client cert file '%s'.\n", optarg); - exit_code(2, __PRETTY_FUNCTION__, "failed to open client cert file"); - } - fclose(pf); - cert_file=optarg; - break; - } -#endif - break; -#endif - case 'a': - if (strlen(optarg) == 1 && STRNCASECMP(optarg, "-", 1) == 0) { - password = str_alloc(SIPSAK_MAX_PASSWD_LEN); - printf("Please enter the password (max. length %i): ", SIPSAK_MAX_PASSWD_LEN); - if (read_stdin(password, SIPSAK_MAX_PASSWD_LEN, 1) == 0) { - exit_code(0, __PRETTY_FUNCTION__, NULL); - } - } - else { - password=str_alloc(strlen(optarg) + 1); - strncpy(password, optarg, strlen(optarg)); - } - break; - case 'A': - timing=str_to_int(0, optarg); - break; - case 'b': - namebeg=str_to_int(0, optarg); - break; - case 'B': - mes_body=str_alloc(strlen(optarg) + 1); - strncpy(mes_body, optarg, strlen(optarg)); - break; - case 'c': - backup=str_alloc(strlen(optarg)+1); - strncpy(backup, optarg, strlen(optarg)); - parse_uri(backup, &scheme, &user, &host, &port); - if (scheme == NULL) { - fprintf(stderr, "error: missing scheme in From URI\n"); - exit_code(2, __PRETTY_FUNCTION__, "missing scheme in From URI"); - } - else if (user == NULL) { - fprintf(stderr, "error: missing username in From URI\n"); - exit_code(2, __PRETTY_FUNCTION__, "missing username in From URI"); - } - else if (host == NULL) { - fprintf(stderr, "error: missing host in From URI\n"); - exit_code(2, __PRETTY_FUNCTION__, "missing host in From URI"); - } - else { - from_uri=str_alloc(strlen(optarg)+1); - strncpy(from_uri, optarg, strlen(optarg)); - } - free(backup); - break; - case 'C': - if ((strlen(optarg) == 5 && STRNCASECMP(optarg, "empty", 5) == 0) || - (strlen(optarg) == 4 && STRNCASECMP(optarg, "none", 4) == 0)) { - empty_contact = 1; - } - else if ((strlen(optarg) == 1 && STRNCASECMP(optarg, "*", 1) == 0) || - (strlen(optarg) == 4 && STRNCASECMP(optarg, "star", 4) == 0)) { - contact_uri=str_alloc(2); - memcpy(contact_uri, "*", 1); - } - else { - backup=str_alloc(strlen(optarg)+1); - strncpy(backup, optarg, strlen(optarg)); - parse_uri(backup, &scheme, &user, &host, &port); - if (scheme == NULL) { - fprintf(stderr, "error: REGISTER Contact uri doesn't not contain " - "sip:, sips:, *, or is not empty\n"); - exit_code(2, __PRETTY_FUNCTION__, "unsupported Contact for registration"); - } - /*else if (user == NULL) { - fprintf(stderr, "error: missing username in Contact uri\n"); - exit_code(2); - }*/ - else if (host == NULL) { - fprintf(stderr, "error: missing host in Contact uri\n"); - exit_code(2, __PRETTY_FUNCTION__, "missing host in Contact"); - } - else { - contact_uri=str_alloc(strlen(optarg)+1); - strncpy(contact_uri, optarg, strlen(optarg)); - } - free(backup); - } - break; - case 'd': - redirects=0; - break; - case 'D': - timer_final = str_to_int(0, optarg); - if (timer_final <= 0) { - fprintf(stderr, "error: option D has to be above 0\n"); - exit_code(2, __PRETTY_FUNCTION__, "option D has to be above 0"); - } - break; - case 'e': - nameend=str_to_int(0, optarg); - break; - case 'E': - if (strlen(optarg) == 3 && - STRNCASECMP(optarg, "udp", 3) == 0) { - transport = SIP_UDP_TRANSPORT; - } - else if (strlen(optarg) == 3 && - STRNCASECMP(optarg, "tcp", 3) == 0) { - transport = SIP_TCP_TRANSPORT; - } -#ifdef WITH_TLS_TRANSP - else if (strlen(optarg) == 3 && - STRNCASECMP(optarg, "tls", 3) == 0) { - transport = SIP_TLS_TRANSPORT; - } -#endif - else { - fprintf(stderr, "error: unsupported transport '%s', supported values: udp, tcp\n", optarg); - exit_code(2, __PRETTY_FUNCTION__, "unsupported transport"); - } - break; - case 'F': - flood=1; - break; - case 'f': - if (strlen(optarg) != 1 && STRNCASECMP(optarg, "-", 1) != 0) { - /* file is opened in binary mode so that the cr-lf is - preserved */ - pf = fopen(optarg, "rb"); - if (!pf){ - fprintf(stderr, "error: unable to open the file '%s'.\n", optarg); - exit_code(2, __PRETTY_FUNCTION__, "failed to open file from the f option"); - } - if (fread(buff, 1, sizeof(buff), pf) >= sizeof(buff)){ - fprintf(stderr, "error:the file is too big. try files of less " - "than %i bytes.\n", BUFSIZE); - fprintf(stderr, " or recompile the program with bigger " - "BUFSIZE defined.\n"); - exit_code(2, __PRETTY_FUNCTION__, "file to big for buffer"); - } - fclose(pf); - } - else if (strlen(optarg) == 1 && STRNCASECMP(optarg, "-", 1) == 0) { - if (read_stdin(&buff[0], sizeof(buff), 0) == 0) { - exit_code(0, __PRETTY_FUNCTION__, NULL); - } - } - else { - fprintf(stderr, "error: unable to handle input file name: %s\n", optarg); - exit_code(2, __PRETTY_FUNCTION__, "unsupported input file name"); - } - file_b=1; - break; - case 'g': - replace_str=optarg; - break; - case 'G': - replace_b=1; - break; - case 'h': - print_help(); - break; - case 'H': - hostname=optarg; - break; - case 'i': - via_ins=0; - break; - case 'I': - invite=1; - break; - case 'j': - headers=optarg; - break; - case 'J': - if (strlen(optarg) < SIPSAK_HASHHEXLEN_MD5) { - fprintf(stderr, "error: authhash string is too short\n"); - exit_code(2, __PRETTY_FUNCTION__, "authhash string is too short"); - } - authhash=optarg; - break; - case 'k': - local_ip=optarg; - break; - case 'K': - sysl=str_to_int(0, optarg); - if (sysl < LOG_ALERT || sysl > LOG_DEBUG) { - fprintf(stderr, "error: syslog value '%s' must be between ALERT (1) and DEBUG (7)\n", optarg); - exit_code(2, __PRETTY_FUNCTION__, "unsupported syslog value for option K"); - } -#ifdef HAVE_SYSLOG_H - openlog(PACKAGE_NAME, LOG_CONS|LOG_NOWAIT|LOG_PID, LOG_USER); -#endif - break; - case 'l': - lport=str_to_int(0, optarg); - break; - case 'L': - fix_crlf=0; - break; - case 'm': - maxforw=str_to_int(0, optarg); - break; - case 'M': - message=1; - break; - case 'n': - numeric = 0; - break; - case 'N': - exit_mode=EM_NAGIOS; - break; - case 'o': - sleep_ms = 0; - if (strlen(optarg) == 4 && STRNCASECMP(optarg, "rand", 4) == 0) { - sleep_ms = -2; - } - else { - sleep_ms = str_to_int(0, optarg); - } - break; - case 'O': - con_dis=str_alloc(strlen(optarg) + 1); - strncpy(con_dis, optarg, strlen(optarg)); - break; - case 'p': - parse_uri(optarg, &scheme, &user, &host, &port); - if (host == NULL) { - fprintf(stderr, "error: missing in host in outbound proxy\n"); - exit_code(2, __PRETTY_FUNCTION__, "missing host in outbound proxy"); - } - if (is_ip(host)) { - address = getaddress(host); - if (transport == 0) - transport = SIP_UDP_TRANSPORT; - } - else { - if (!port) { - address = getsrvadr(host, &rport, &tsp); - if (tsp != 0) - transport = tsp; - } - if (!address) { - address = getaddress(host); - if (address && verbose > 1) - printf("using A record: %s\n", host); - } - if (!address){ - fprintf(stderr, "error:unable to determine the outbound proxy " - "address\n"); - exit_code(2, __PRETTY_FUNCTION__, "failed to resolve the outbound proxy"); - } - } - if (port && !rport) { - rport = port; - } - outbound_proxy=1; -#ifdef DEBUG - printf("address: %lu, rport: %i\n", address, rport); -#endif - break; - case 'P': - processes=str_to_int(0, optarg); - break; - case 'q': - if (re) { - /* previously allocated -- free */ - regfree(re); - } else { - /* never tried -- allocate */ - re=malloc(sizeof(regex_t)); - }; - if (!re) { - fprintf(stderr, "Error: can't allocate RE\n"); - exit_code(2, __PRETTY_FUNCTION__, "failed to allocate memory for regualr expression"); - }; - if (regcomp(re, optarg, REG_EXTENDED|REG_ICASE|REG_NEWLINE )!=0) { - fprintf(stderr, "Error: compiling RE: %s\n", optarg ); - exit_code(2, __PRETTY_FUNCTION__, "failed to compile regular expression"); - }; - break; - case 'r': - port=str_to_int(0, optarg); - if (rport) { - fprintf(stderr, "warning: you are overwritting the destination port with the r argument\n"); - } - rport = port; - break; - case 'R': - randtrash=1; - break; - case 's': - parse_uri(optarg, &scheme, &user, &host, &port); - if (scheme == NULL) { - fprintf(stderr, "error: missing scheme in sip uri\n"); - exit_code(2, __PRETTY_FUNCTION__, "missing scheme in target SIP URI"); - } - if (strlen(optarg) == 4 && STRNCASECMP(optarg,"sips",4) == 0){ - fprintf(stderr, "error: sips is not supported yet\n"); - exit_code(2, __PRETTY_FUNCTION__, "unsupported scheme SIPS in target URI"); - } - else if (strlen(optarg) != 3 || STRNCASECMP(optarg,"sip",3) != 0){ - fprintf(stderr, "error: scheme of sip uri has to be sip\n"); - exit_code(2, __PRETTY_FUNCTION__, "unsupported scheme in target URI"); - } - if (user != NULL) { - username = user; - } - if (host != NULL) { - domainname = host; - } - else { - fprintf(stderr, "error: missing hostname in sip uri\n"); - exit_code(2, __PRETTY_FUNCTION__, "missing host name in target URI"); - } - if (port && !rport) { - rport = port; - } - if (is_ip(domainname) && !address) { - address = getaddress(domainname); - if (transport == 0) - transport = SIP_UDP_TRANSPORT; - } - else { - if (!rport && !address) { - address = getsrvadr(domainname, &rport, &tsp); - if (tsp != 0 && transport == 0) - transport = tsp; - } - if (!address) { - address = getaddress(domainname); - if (address && verbose > 1) - printf("using A record: %s\n", domainname); - } - if (!address){ - fprintf(stderr, "error:unable to determine the IP address for: %s\n", domainname); - exit_code(2, __PRETTY_FUNCTION__, "failed to resolve host from target URI"); - } - } - if (port != 0) { - backup = str_alloc(strlen(domainname)+1+6); - snprintf(backup, strlen(domainname)+6, "%s:%i", domainname, port); - domainname = backup; - } - uri_b=1; -#ifdef DEBUG - printf("address: %lu, rport: %i, username: '%s', domain: '%s'\n", address, rport, username, domainname); -#endif - break; - case 'S': - fprintf(stderr, "warning: symmetric does not work with a-symmetric servers\n"); - symmetric=1; - break; - case 't': - trashchar=str_to_int(0, optarg); - break; - case 'T': - trace=1; - break; - case 'U': - usrloc=1; - break; - case 'u': - auth_username=str_alloc(strlen(optarg) + 1); - strncpy(auth_username, optarg, strlen(optarg)); - break; - case 'v': - verbose++; - break; - case 'V': - printf("sipsak %s by Nils Ohlmeier\n Copyright (C) 2002-2004" - " FhG Fokus\n Copyright (C) 2004-2005 Nils Ohlmeier\n", - SIPSAK_VERSION); - printf(" compiled with DEFAULT_TIMEOUT=%i, FQDN_SIZE=%i", - DEFAULT_TIMEOUT, FQDN_SIZE); -#ifdef RAW_SUPPORT - printf(", RAW_SUPPORT"); -#endif -#ifdef HAVE_GETOPT_LONG - printf(", LONG_OPTS"); -#endif -#ifdef HAVE_FULL_OPENSSL - printf(", OPENSSL_MD5"); -#else - printf(", INTERNAL_MD5"); -#endif -#ifdef HAVE_OPENSSL_SHA1 - printf(", OPENSSL_SHA1"); -#endif -#ifdef WITH_TLS_TRANSP -# ifdef USE_GNUTLS - printf(", TLS_SUPPORT(GNUTLS)"); -# else -# ifdef USE_OPENSSL - printf(", TLS_SUPPORT(OPENSSL)"); -# endif -# endif -#endif -#ifdef HAVE_CARES_H - printf(", SRV_SUPPORT(ARES)"); -#else -# ifdef HAVE_RULI_H - printf(", SRV_SUPPORT(RULI)"); -# endif -#endif -#ifdef HAVE_STRCASESTR - printf(", STR_CASE_INSENSITIVE"); -#endif -#ifdef HAVE_STRNCASECMP - printf(", CMP_CASE_INSENSITIVE"); -#endif -#ifdef DEBUG - printf(", DEBUG"); -#endif - printf("\n"); - exit_code(0, __PRETTY_FUNCTION__, NULL); - break; - case 'w': - warning_ext=1; - break; - case 'W': - nagios_warn = str_to_int(0, optarg); - break; - case 'x': - expires_t=str_to_int(0, optarg); - break; - case 'z': - rand_rem=str_to_int(0, optarg); - if (rand_rem < 0 || rand_rem > 100) { - fprintf(stderr, "error: z option must between 0 and 100\n"); - exit_code(2, __PRETTY_FUNCTION__, "value for option z out of range"); - } - break; - case 'Z': - timer_t1 = str_to_int(0, optarg); - if (timer_t1 <= 0) { - fprintf(stderr, "error: Z option must be above 0\n"); - exit_code(2, __PRETTY_FUNCTION__, "value for option Z must be above 0"); - } - break; - default: - fprintf(stderr, "error: unknown parameter '%c'\n", c); - exit_code(2, __PRETTY_FUNCTION__, "unknown parameter"); - break; - } - } - - if (rport == 0) { - rport = 5060; - } - if (rport > 65535 || rport <= 0) { - fprintf(stderr, "error: invalid remote port: %i\n", rport); - exit_code(2, __PRETTY_FUNCTION__, "remote port out of range"); - } - if (transport == 0) { - transport = SIP_UDP_TRANSPORT; - } - - timer_t2 = timer_t2 * timer_t1; - timer_final = timer_final * timer_t1; - - /* replace LF with CRLF if we read from a file */ - if ((file_b) && (fix_crlf)) { - insert_cr(buff); - } - if (headers) { - backup = str_alloc(strlen(headers) + 30); // FIXME - strcpy(backup, headers); - headers = backup; - replace_string(headers, "\\n", "\r\n"); - backup = headers + strlen(headers) - 1; - if (*backup != '\n') { - strcpy(backup + 1, "\r\n"); - } - if (file_b) - insert_header(buff, headers, 1); - } - /* lots of conditions to check */ - if (trace) { - if (usrloc || flood || randtrash) { - fprintf(stderr, "error: trace can't be combined with usrloc, random or " - "flood\n"); - exit_code(2, __PRETTY_FUNCTION__, "trace mode can't be combined with other modes"); - } - if (!uri_b) { - fprintf(stderr, "error: for trace mode a SIPURI is really needed\n"); - exit_code(2, __PRETTY_FUNCTION__, "missing URI for trace mode"); - } - if (file_b) { - fprintf(stderr, "warning: file will be ignored for tracing."); - } - if (!username) { - fprintf(stderr, "error: for trace mode without a file the SIPURI have to " - "contain a username\n"); - exit_code(2, __PRETTY_FUNCTION__, "missing username in target URI"); - } - if (!via_ins){ - fprintf(stderr, "warning: Via-Line is needed for tracing. Ignoring -i\n"); - via_ins=1; - } - if (!warning_ext) { - fprintf(stderr, "warning: IP extract from warning activated to be more " - "informational\n"); - warning_ext=1; - } - if (maxforw==-1) maxforw=255; - } - else if (usrloc || invite || message) { - if (trace || flood || randtrash) { - fprintf(stderr, "error: usrloc can't be combined with trace, random or " - "flood\n"); - exit_code(2, __PRETTY_FUNCTION__, "usrloc mode can't be combined with other modes"); - } - if (!username || !uri_b) { - fprintf(stderr, "error: for the USRLOC mode you have to give a SIPURI with " - "a username\n at least\n"); - exit_code(2, __PRETTY_FUNCTION__, "missing target URI or username in URI"); - } - if (namebeg>0 && nameend==-1) { - fprintf(stderr, "error: if a starting numbers is given also an ending " - "number have to be specified\n"); - exit_code(2, __PRETTY_FUNCTION__, "missing end number"); - } - if (invite && message) { - fprintf(stderr, "error: invite and message tests are XOR\n"); - exit_code(2, __PRETTY_FUNCTION__, "INVITE and MESSAGE tests are XOR"); - } - if (!usrloc && invite && !lport) { - fprintf(stderr, "warning: Do NOT use the usrloc invite mode without " - "registering sipsak before.\n See man page for " - "details.\n"); - exit_code(2, __PRETTY_FUNCTION__, "don't use usrloc INVITE mode without registerting before"); - } - if (contact_uri!=NULL) { - if (invite || message) { - fprintf(stderr, "error: Contact uri is not support for invites or " - "messages\n"); - exit_code(2, __PRETTY_FUNCTION__, "Contact URI not supported for INVITE or MESSAGE mode"); - } - if (nameend!=-1 || namebeg!=-1) { - fprintf(stderr, "warning: ignoring starting or ending number if Contact" - " is given\n"); - nameend=namebeg=0; - } - if (rand_rem) { - fprintf(stderr, "warning: ignoring -z option when Contact is given\n"); - rand_rem=0; - } - } - if (via_ins) { - if (verbose > 1) { - fprintf(stderr, "warning: Deactivated Via insertion in usrloc mode.\n Please use option -i to suppress this warning.\n"); - } - via_ins=0; - } - if (nameend==-1) - nameend=0; - if (namebeg==-1) - namebeg=0; - } - else if (flood) { - if (trace || usrloc || randtrash) { - fprintf(stderr, "error: flood can't be combined with trace, random or " - "usrloc\n"); - exit_code(2, __PRETTY_FUNCTION__, "flood mode can't be combined with other modes"); - } - if (!uri_b) { - fprintf(stderr, "error: we need at least a sip uri for flood\n"); - exit_code(2, __PRETTY_FUNCTION__, "missing target URI"); - } - if (redirects) { - fprintf(stderr, "warning: redirects are not expected in flood. " - "disableing\n"); - redirects=0; - } - } - else if (randtrash) { - if (trace || usrloc || flood) { - fprintf(stderr, "error: random can't be combined with trace, flood or " - "usrloc\n"); - exit_code(2, __PRETTY_FUNCTION__, "random mode can't be combined with other modes"); - } - if (!uri_b) { - fprintf(stderr, "error: need at least a sip uri for random\n"); - exit_code(2, __PRETTY_FUNCTION__, "missing target URI"); - } - if (redirects) { - fprintf(stderr, "warning: redirects are not expected in random. " - "disableing\n"); - redirects=0; - } - if (verbose) { - fprintf(stderr, "warning: random characters may destroy your terminal " - "output\n"); - } - } - else if (mes_body) { - if (!message) { - fprintf(stderr, "warning: to send a message mode (-M) is required. activating\n"); - message=1; - } - if (!uri_b) { - fprintf(stderr, "error: need at least a sip uri to send a meesage\n"); - exit_code(2, __PRETTY_FUNCTION__, "missing target SIP URI"); - } - if (nameend==-1) - nameend=0; - if (namebeg==-1) - namebeg=0; - } - else { - if (!uri_b) { - fprintf(stderr, "error: a spi uri is needed at least\n"); - exit_code(2, __PRETTY_FUNCTION__, "missing target SIP URI"); - } - } - - switch (transport) { -#ifdef WITH_TLS_TRANSP - case SIP_TLS_TRANSPORT: - transport_str = TRANSPORT_TLS_STR; - break; -#endif /* WITH_TLS_TRANSP */ - case SIP_TCP_TRANSPORT: - transport_str = TRANSPORT_TCP_STR; - break; - case SIP_UDP_TRANSPORT: - transport_str = TRANSPORT_UDP_STR; - break; - default: - fprintf(stderr, "unknown transport: %u\n", transport); - exit_code(2, __PRETTY_FUNCTION__, "unknown transport"); - } - -#ifdef WITH_TLS_TRANSP - if (transport == SIP_TLS_TRANSPORT) { -# ifdef USE_GNUTLS - gnutls_global_init(); - //gnutls_anon_allocate_client_credentials(&anoncred); - gnutls_certificate_allocate_credentials(&xcred); - if (ca_file != NULL) { - // set the trusted CA file - gnutls_certificate_set_x509_trust_file(xcred, ca_file, GNUTLS_X509_FMT_PEM); - } -# else -# ifdef USE_OPENSSL - SSL_library_init(); - SSL_load_error_strings(); -# endif -# endif - } -#endif /* WITH_TLS_TRANSP */ - - /* determine our hostname */ - get_fqdn(); - - /* this is not a cryptographic random number generator, - but hey this is only a test-tool => should be satisfying*/ - srand(time(0) ^ (getpid() + (getpid() << 15))); - - if (processes > 1) { - if (signal(SIGCHLD , sigchld_handler) == SIG_ERR ) { - fprintf(stderr, "error: Could not install SIGCHLD handler\n"); - exit_code(2, __PRETTY_FUNCTION__, "failed to install SIGCHLD handler"); - } - } - - for(i = 0; i < processes - 1; i++) { - if ((pid = fork()) < 0) { - fprintf(stderr, "error: Cannot fork\n"); - exit_code(2, __PRETTY_FUNCTION__, "failed to fork"); - } - - if (pid == 0){ - /* child */ - upp = (nameend - namebeg + 1) / processes; - namebeg = namebeg + upp * i; - nameend = namebeg + upp; - shoot(&buff[0], sizeof(buff)); - } else { - if (lport) { - lport++; - } - } - - /* Delay execution of children so that the - * time of the first transmission gets spread over - * the retransmission interval evenly - */ - ts.tv_sec = 0; - ts.tv_nsec = (float)DEFAULT_TIMEOUT / (float)processes * (float)1000 * (float)1000; - nanosleep(&ts, 0); - } - - /* here we go...*/ - if (processes > 1) { - upp = (nameend - namebeg + 1) / processes; - namebeg = namebeg + upp * i; - nameend = namebeg + upp; - } - shoot(&buff[0], sizeof(buff)); - - /* normaly we won't come back here, but to satisfy the compiler */ - return 0; -} - diff -Nru sipsak-0.9.6+git20170713/sipsak.h sipsak-0.9.7/sipsak.h --- sipsak-0.9.6+git20170713/sipsak.h 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/sipsak.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,340 +0,0 @@ -/* - * Copyright (C) 2002-2004 Fhg Fokus - * Copyright (C) 2004-2005 Nils Ohlmeier - * - * This file belongs to sipsak, a free sip testing tool. - * - * sipsak is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * sipsak is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef SIPSAK_H -#define SIPSAK_H - -#if HAVE_CONFIG_H -# include "config.h" -#endif - -#ifdef HAVE_STDIO_H -# include -#endif -#ifdef HAVE_STDLIB_H -# include -#endif -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_REGEX_H -# include -#endif -#ifdef HAVE_SYS_PARAM_H -# include -#endif -#ifdef HAVE_NETINET_IN_H -# include -#endif -#ifndef INET_ADDRSTRLEN -# define INET_ADDRSTRLEN 16 -#endif -#ifdef HAVE_SIGNAL_H -# include -#endif - -#ifdef HAVE_LIMITS_H -# include -#endif -#ifndef INT_MAX -# define INT_MAX 2147483648 -#endif - -#ifdef HAVE_STRCASESTR -# define __USE_GNU -# define STRCASESTR(s1,s2) strcasestr(s1,s2) -#else -# define STRCASESTR(s1,s2) strstr(s1,s2) -#endif -#ifdef HAVE_STRNCASECMP -# define STRNCASECMP(s1,s2,s3) strncasecmp(s1,s2,s3) -#else -# define STRNCASECMP(s1,s2,s3) strncmp(s1,s2,s3) -#endif -#ifdef HAVE_STRING_H -# include -#endif - -#ifdef HAVE_GNUTLS -# define USE_GNUTLS -# ifndef SIPSAK_NO_TLS -# define WITH_TLS_TRANSP 1 -# endif -# include -#else -# ifdef HAVE_OPENSSL_MD5_H -# ifdef HAVE_CRYPTO_WITH_MD5 -# define HAVE_FULL_OPENSSL -# define HAVE_EXTERNAL_MD5 -# define USE_OPENSSL -# include -# endif -# endif -#endif - -#ifdef HAVE_OPENSSL_SHA_H -# ifdef HAVE_CRYPTO_WITH_SHA1 -# define HAVE_OPENSSL_SHA1 -# endif -#endif - -#ifdef SIPSAK_PRINT_DBG -# define DEBUG 1 -#endif - -#ifndef REG_NOERROR -# define REG_NOERROR 0 -#endif - -#ifdef HAVE_SYS_PARAM_H -# ifdef MAXHOSTNAMELEN -# define FQDN_SIZE MAXHOSTNAMELEN + 1 -# else -# define FQDN_SIZE 100 -# endif -#else -# define FQDN_SIZE 100 -#endif - -#ifdef HAVE_CONFIG_H -# define SIP_T1 DEFAULT_TIMEOUT -#else -# define SIP_T1 500 -#endif - -#define SIP_T2 8*SIP_T1 - -#define SIPSAK_VERSION PACKAGE_VERSION -#define UA_VAL_STR "sipsak " SIPSAK_VERSION -#define BUFSIZE 4096 - -#define SIPSAK_MAX_PASSWD_LEN 20 - -#define REQ_REG 1 -#define REQ_REM 2 -#define REQ_INV 3 -#define REQ_MES 4 -#define REQ_OPT 5 -#define REQ_FLOOD 6 -#define REQ_RAND 7 - -#define SIP_TLS_TRANSPORT 1 -#define SIP_TCP_TRANSPORT 2 -#define SIP_UDP_TRANSPORT 3 - -#define TRANSPORT_TLS_STR "TLS" -#define TRANSPORT_TCP_STR "TCP" -#define TRANSPORT_UDP_STR "UDP" -#define TRANSPORT_STR_LEN 3 - -#define VIA_SIP_STR "Via: SIP/2.0/" -#define VIA_SIP_STR_LEN (sizeof(VIA_SIP_STR) - 1) - -#define SIP20_STR " SIP/2.0\r\n" -#define SIP20_STR_LEN (sizeof(SIP20_STR) - 1) - -#define SIP200_STR "SIP/2.0 200 OK\r\n" -#define SIP200_STR_LEN (sizeof(SIP200_STR) - 1) - -#define INV_STR "INVITE" -#define INV_STR_LEN (sizeof(INV_STR) - 1) - -#define REG_STR "REGISTER" -#define REG_STR_LEN (sizeof(REG_STR) - 1) - -#define OPT_STR "OPTIONS" -#define OPT_STR_LEN (sizeof(OPT_STR) - 1) - -#define MES_STR "MESSAGE" -#define MES_STR_LEN (sizeof(MES_STR) - 1) - -#define ACK_STR "ACK" -#define ACK_STR_LEN (sizeof(ACK_STR) - 1) - -#define FROM_STR "From: " -#define FROM_STR_LEN (sizeof(FROM_STR) - 1) -#define FROM_SHORT_STR "\nf: " -#define FROM_SHORT_STR_LEN (sizeof(FROM_SHORT_STR) - 1) - -#define TO_STR "To: " -#define TO_STR_LEN (sizeof(TO_STR) - 1) -#define TO_SHORT_STR "\nt: " -#define TO_SHORT_STR_LEN (sizeof(TO_SHORT_STR) - 1) - -#define VIA_STR "Via: " -#define VIA_STR_LEN (sizeof(VIA_STR) - 1) -#define VIA_SHORT_STR "\nv: " -#define VIA_SHORT_STR_LEN (sizeof(VIA_SHORT_STR) - 1) - -#define CALL_STR "Call-ID: " -#define CALL_STR_LEN (sizeof(CALL_STR) - 1) -#define CALL_SHORT_STR "\ni: " -#define CALL_SHORT_STR_LEN (sizeof(CALL_SHORT_STR) - 1) - -#define MAX_FRW_STR "Max-Forwards: " -#define MAX_FRW_STR_LEN (sizeof(MAX_FRW_STR) - 1) - -#define CSEQ_STR "CSeq: " -#define CSEQ_STR_LEN (sizeof(CSEQ_STR) - 1) - -#define CONT_STR "Contact: " -#define CONT_STR_LEN (sizeof(CONT_STR) - 1) -#define CONT_SHORT_STR "\nm: " -#define CONT_SHORT_STR_LEN (sizeof(CONT_SHORT_STR) - 1) - -#define CON_TYP_STR "Content-Type: " -#define CON_TYP_STR_LEN (sizeof(CON_TYP_STR) - 1) -#define CON_TYP_SHORT_STR "\nc: " -#define CON_TYP_SHORT_STR_LEN (sizeof(CON_TYP_SHORT_STR) - 1) - -#define CON_DIS_STR "Content-Disposition: " -#define CON_DIS_STR_LEN (sizeof(CON_DIS_STR) - 1) - -#define TXT_PLA_STR "text/plain" -#define TXT_PLA_STR_LEN (sizeof(TXT_PLA_STR) - 1) - -#define ACP_STR "Accept: " -#define ACP_STR_LEN (sizeof(ACP_STR) - 1) - -#define CON_LEN_STR "Content-Length: " -#define CON_LEN_STR_LEN (sizeof(CON_LEN_STR) - 1) -#define CON_LEN_SHORT_STR "\nl: " -#define CON_LEN_SHORT_STR_LEN (sizeof(CON_LEN_SHORT_STR) - 1) - -#define RR_STR "Record-Route: " -#define RR_STR_LEN (sizeof(RR_STR) - 1) - -#define ROUTE_STR "Route: " -#define ROUTE_STR_LEN (sizeof(ROUTE_STR) - 1) - -#define SIPSAK_MES_STR "test message from SIPsak for user " -#define SIPSAK_MES_STR_LEN (sizeof(SIPSAK_MES_STR) - 1) - -#define EXP_STR "Expires: " -#define EXP_STR_LEN (sizeof(EXP_STR) - 1) - -#define CON_EXP_STR "expires=" -#define CON_EXP_STR_LEN (sizeof(CON_EXP_STR) - 1) - -#define WWWAUTH_STR "WWW-Authenticate: " -#define WWWAUTH_STR_LEN (sizeof(WWWAUTH_STR) - 1) - -#define PROXYAUTH_STR "Proxy-Authenticate: " -#define PROXYAUTH_STR_LEN (sizeof(PROXYAUTH_STR) - 1) - -#define AUTH_STR "Authorization: Digest " -#define AUTH_STR_LEN (sizeof(AUTH_STR) - 1) - -#define PROXYAUZ_STR "Proxy-Authorization: Digest " -#define PROXYAUZ_STR_LEN (sizeof(PROXYAUZ_STR) - 1) - -#define ALGO_STR "algorithm=" -#define ALGO_STR_LEN (sizeof(ALGO_STR) - 1) - -#define MD5_STR "MD5, " -#define MD5_STR_LEN (sizeof(MD5_STR) - 1) - -#define SHA1_STR "SHA1, " -#define SHA1_STR_LEN (sizeof(SHA1_STR) - 1) - -#define SHA256_STR "SHA-256, " -#define SHA256_STR_LEN (sizeof(SHA256_STR) - 1) - -#define REALM_STR "realm=" -#define REALM_STR_LEN (sizeof(REALM_STR) - 1) - -#define OPAQUE_STR "opaque=" -#define OPAQUE_STR_LEN (sizeof(OPAQUEE_STR) - 1) - -#define NONCE_STR "nonce=" -#define NONCE_STR_LEN (sizeof(NONCE_STR) - 1) - -#define RESPONSE_STR "response=" -#define RESPONSE_STR_LEN (sizeof(RESPONSE_STR) - 1) - -#define QOP_STR "qop=" -#define QOP_STR_LEN (sizeof(QOP_STR) - 1) - -#define QOPAUTH_STR "auth" -#define QOPAUTH_STR_LEN (sizeof(QOPAUTH_STR) - 1) - -#define NC_STR "nc=" -#define NC_STR_LEN (sizeof(NC_STR) - 1) - -#define EMPTY_STR "" -#define EMPTY_STR_LEN (sizeof(EMPTY_STR) - 1) - -#define UA_STR "User-Agent: " -#define UA_STR_LEN (sizeof(UA_STR) - 1) - -#define SUB_STR "Subject: " -#define SUB_STR_LEN (sizeof(SUB_STR) - 1) - -#define SIP100_STR "SIP/2.0 100" -#define SIP100_STR_LEN (sizeof(SIP100_STR) - 1) - -#define TRANSPORT_PARAMETER_STR ";transport=" -#define TRANSPORT_PARAMETER_STR_LEN (sizeof(TRANSPORT_PARAMETER_STR) - 1) - -#define USRLOC_EXP_DEF 15 -#define FLOOD_METH "OPTIONS" - -#define SIPSAK_HASHLEN_MD5 16 -#define SIPSAK_HASHHEXLEN_MD5 2 * SIPSAK_HASHLEN_MD5 -#ifdef HAVE_OPENSSL_SHA1 -# define SIPSAK_HASHLEN_SHA1 20 -# define SIPSAK_HASHHEXLEN_SHA1 2 * SIPSAK_HASHLEN_SHA1 -# define SIPSAK_HASHLEN_SHA256 32 -# define SIPSAK_HASHHEXLEN_SHA256 2 * SIPSAK_HASHLEN_SHA256 -# define SIPSAK_HASHLEN SIPSAK_HASHLEN_SHA256 -#else -# define SIPSAK_HASHLEN SIPSAK_HASHLEN_MD5 -#endif -#define SIPSAK_HASHHEXLEN 2 * SIPSAK_HASHLEN - -#ifdef WITH_TLS_TRANSP -char *cert_file, *ca_file; -int ignore_ca_fail; -# ifdef USE_GNUTLS -gnutls_session_t tls_session; -//gnutls_anon_client_credentials_t anoncred; -gnutls_certificate_credentials_t xcred; -# else -# ifdef USE_OPENSSL -SSL_CTX* ctx; -SSL* ssl; -# endif -# endif -#endif - -/* lots of global variables. ugly but makes life easier. */ -unsigned long address; -unsigned int nonce_count, transport; -int sleep_ms, processes, cseq_counter; -int verbose, nameend, namebeg, expires_t, flood, warning_ext, invite, message; -int maxforw, lport, rport, randtrash, trashchar, numeric, symmetric; -int file_b, uri_b, trace, via_ins, usrloc, redirects, rand_rem, replace_b; -int empty_contact, nagios_warn, fix_crlf, timing, outbound_proxy; -int timer_t1, timer_t2, timer_final, sysl; -char *username, *domainname, *password, *replace_str, *hostname, *contact_uri; -char *mes_body, *con_dis, *auth_username, *from_uri, *headers, *authhash, *local_ip; -char fqdn[FQDN_SIZE]; -char target_dot[INET_ADDRSTRLEN], source_dot[INET_ADDRSTRLEN]; -char *req, *rep, *rec, *transport_str; -regex_t* re; - -#endif diff -Nru sipsak-0.9.6+git20170713/src/auth.c sipsak-0.9.7/src/auth.c --- sipsak-0.9.6+git20170713/src/auth.c 1970-01-01 00:00:00.000000000 +0000 +++ sipsak-0.9.7/src/auth.c 2019-04-27 04:54:34.000000000 +0000 @@ -0,0 +1,402 @@ +/* + * Copyright (C) 2002-2004 Fhg Fokus + * Copyright (C) 2004-2005 Nils Ohlmeier + * + * This file belongs to sipsak, a free sip testing tool. + * + * sipsak is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * sipsak is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "sipsak.h" +#include "auth.h" +#include "exit_code.h" +#include "helper.h" +#include "md5.h" + +#ifdef HAVE_OPENSSL_SHA1 +# include +#endif + +#define SIPSAK_ALGO_MD5 1 +#define SIPSAK_ALGO_SHA1 2 +#define SIPSAK_ALGO_SHA256 3 + +/* converts a hash into hex output + taken from the RFC 2617 */ +void cvt_hex(unsigned char *_b, unsigned char *_h, int length) +{ + unsigned short i; + + for (i = 0; i < length; i++) { + unsigned char j; + j = (_b[i] >> 4) & 0xf; + if (j <= (unsigned char)9) { + _h[i * 2] = (j + (unsigned char)'0'); + } else { + _h[i * 2] = (unsigned char)(j + (unsigned char)'a' - (unsigned char)10); + } + j = _b[i] & 0xf; + if (j <= (unsigned char)9) { + _h[i * 2 + 1] = (j + (unsigned char)'0'); + } else { + _h[i * 2 + 1] = (unsigned char)(j + (unsigned char)'a' - (unsigned char)10); + } + }; + _h[2*length] = '\0'; +} + +/* check for, create and insert a auth header into the message */ +void insert_auth(char *message, char *authreq) +{ + char *auth, *begin, *end, *insert, *backup, *realm, *usern, *nonce; + char *method, *uri; + char *qop_tmp = NULL; + unsigned char ha1[SIPSAK_HASHLEN], ha2[SIPSAK_HASHLEN], resp[SIPSAK_HASHLEN]; + unsigned char ha1_hex[SIPSAK_HASHHEXLEN+1], ha2_hex[SIPSAK_HASHHEXLEN+1], resp_hex[SIPSAK_HASHHEXLEN+1]; + int qop_auth=0, proxy_auth=0, algo=0; + MD5_CTX Md5Ctx; +#ifdef HAVE_OPENSSL_SHA1 + SHA_CTX Sha1Ctx; + SHA256_CTX Sha256Ctx; +#endif + + auth=begin=end=insert=backup=realm=usern=nonce=method=uri = NULL; + + memset(&ha1[0], '\0', SIPSAK_HASHLEN); + memset(&ha2[0], '\0', SIPSAK_HASHLEN); + memset(&resp[0], '\0', SIPSAK_HASHLEN); + memset(&ha1_hex[0], '\0', SIPSAK_HASHHEXLEN+1); + memset(&ha2_hex[0], '\0', SIPSAK_HASHHEXLEN+1); + memset(&resp_hex[0], '\0', SIPSAK_HASHHEXLEN+1); + + /* prevent double auth insertion */ + if ((begin=STRCASESTR(message, AUTH_STR))!=NULL || + (begin=STRCASESTR(message, PROXYAUZ_STR))!=NULL) { + fprintf(stderr, "request:\n%s\nresponse:\n%s\nerror: authorization failed\n " + " request already contains (Proxy-) Authorization, but " + "received 40[1|7], see above\n", message, authreq); + exit_code(2, __PRETTY_FUNCTION__, "failed to add auth header, because request contained already one"); + } + /* make a backup of all except the request line because for + simplicity we insert the auth header direct behind the request line */ + insert=strchr(message, '\n'); + if (!insert) { + printf("failed to find newline\n"); + return; + } + insert++; + backup=str_alloc(strlen(insert)+1); + strncpy(backup, insert, strlen(insert)); + + begin=STRCASESTR(authreq, WWWAUTH_STR); + if (begin==NULL) { + begin=STRCASESTR(authreq, PROXYAUTH_STR); + proxy_auth = 1; + } + if (begin) { + /* make a copy of the auth header to prevent that our searches + hit content of other header fields */ + end=strchr(begin, '\n'); + auth=str_alloc((size_t)(end-begin+1)); + strncpy(auth, begin, (size_t)(end-begin)); + /* we support Digest with MD5 or SHA1 */ + if ((begin=STRCASESTR(auth, "Basic"))!=NULL) { + fprintf(stderr, "%s\nerror: authentication method Basic is deprecated since" + " RFC 3261 and not supported by sipsak\n", authreq); + exit_code(3, __PRETTY_FUNCTION__, "authentication method 'Basic' is deprecated"); + } + if ((begin=STRCASESTR(auth, "Digest"))==NULL) { + fprintf(stderr, "%s\nerror: couldn't find authentication method Digest in " + "the 40[1|7] response above\n", authreq); + exit_code(3, __PRETTY_FUNCTION__, "missing authentication method 'Digest' in reply"); + } + if ((begin=STRCASESTR(auth, "algorithm="))!=NULL) { + begin+=10; + if ((STRNCASECMP(begin, "MD5", 3))==0 || (STRNCASECMP(begin, "\"MD5\"", 5))==0) { + algo = SIPSAK_ALGO_MD5; + } +#ifdef HAVE_OPENSSL_SHA1 + else if ((STRNCASECMP(begin, "SHA1", 4))==0 || (STRNCASECMP(begin, "\"SHA1\"", 6))==0) { + algo = SIPSAK_ALGO_SHA1; + } + else if ((STRNCASECMP(begin, "SHA-256", 7))==0 || (STRNCASECMP(begin, "\"SHA-256\"", 9))==0) { + algo = SIPSAK_ALGO_SHA256; + } +#endif + else { + fprintf(stderr, "\n%s\nerror: unsupported authentication algorithm\n", authreq); + exit_code(2, __PRETTY_FUNCTION__, "unsupported authentication algorithm"); + } + } + else { + algo = SIPSAK_ALGO_MD5; + } + /* we need the username at some points */ + if (auth_username != NULL) { + usern = auth_username; + } + else { + usern=str_alloc(strlen(username)+11); + if (nameend>0) + snprintf(usern, strlen(username)+10, "%s%i", username, namebeg); + else + snprintf(usern, strlen(username)+10, "%s", username); + } + /* extract the method from the original request */ + end=strchr(message, ' '); + method=str_alloc((size_t)(end-message+1)); + strncpy(method, message, (size_t)(end-message)); + /* extract the uri also */ + begin=end++; + begin++; + end=strchr(end, ' '); + uri=str_alloc((size_t)(end-begin+1)); + strncpy(uri, begin, (size_t)(end-begin)); + + /* lets start with some basic stuff... username, uri and algorithm */ + if (proxy_auth == 1) { + snprintf(insert, PROXYAUZ_STR_LEN+1, PROXYAUZ_STR); + insert+=PROXYAUZ_STR_LEN; + } + else { + snprintf(insert, AUTH_STR_LEN+1, AUTH_STR); + insert+=AUTH_STR_LEN; + } + snprintf(insert, strlen(usern)+14, "username=\"%s\", ", usern); + insert+=strlen(insert); + snprintf(insert, strlen(uri)+9, "uri=\"%s\", ", uri); + insert+=strlen(insert); + snprintf(insert, ALGO_STR_LEN+1, ALGO_STR); + insert+=ALGO_STR_LEN; + if (algo == SIPSAK_ALGO_MD5) { + snprintf(insert, MD5_STR_LEN+1, MD5_STR); + insert+=MD5_STR_LEN; + } +#ifdef HAVE_OPENSSL_SHA1 + else if (algo == SIPSAK_ALGO_SHA1) { + snprintf(insert, SHA1_STR_LEN+1, SHA1_STR); + insert+=SHA1_STR_LEN; + } + else if (algo == SIPSAK_ALGO_SHA256) { + snprintf(insert, SHA256_STR_LEN+1, SHA256_STR); + insert+=SHA256_STR_LEN; + } +#endif + /* search for the realm, copy it to request and extract it for hash*/ + if ((begin=STRCASESTR(auth, REALM_STR))!=NULL) { + end=strchr(begin, ','); + if (!end) + end=strchr(begin, '\r'); + strncpy(insert, begin, (size_t)(end-begin+1)); + insert=insert+(end-begin+1); + if (*(insert-1) == '\r') + *(insert-1)=','; + snprintf(insert, 2, " "); + insert++; + begin+=REALM_STR_LEN+1; + end--; + realm=str_alloc((size_t)(end-begin+1)); + strncpy(realm, begin, (size_t)(end-begin)); + } + else { + fprintf(stderr, "%s\nerror: realm not found in 401 above\n", authreq); + exit_code(3, __PRETTY_FUNCTION__, "realm not found in reply"); + } + /* copy opaque if needed */ + if ((begin=STRCASESTR(auth, OPAQUE_STR))!=NULL) { + end=strchr(begin, ','); + if (!end) { + end=strchr(begin, '\r'); + } + strncpy(insert, begin, (size_t)(end-begin+1)); + insert=insert+(end-begin+1); + if (*(insert-1) == '\r') + *(insert-1)=','; + snprintf(insert, 2, " "); + insert++; + } + /* lets see if qop=auth is uspported */ + if ((begin=STRCASESTR(auth, QOP_STR))!=NULL) { + if (STRCASESTR(begin, QOPAUTH_STR)==NULL) { + fprintf(stderr, "response\n%s\nerror: qop \"auth\" not supported by" + " server\n", authreq); + exit_code(3, __PRETTY_FUNCTION__, "qop 'auth' is not supported by server"); + } + qop_auth=1; + } + /* search, copy and extract the nonce */ + if ((begin=STRCASESTR(auth, NONCE_STR))!=NULL) { + end=strchr(begin, ','); + if (!end) + end=strchr(begin, '\r'); + strncpy(insert, begin, (size_t)(end-begin+1)); + insert=insert+(end-begin+1); + if (*(insert-1) == '\r') + *(insert-1)=','; + snprintf(insert, 2, " "); + insert++; + begin+=NONCE_STR_LEN+1; + end--; + nonce=str_alloc((size_t)(end-begin+1)); + strncpy(nonce, begin, (size_t)(end-begin)); + } + else { + fprintf(stderr, "%s\nerror: nonce not found in 401 above\n", authreq); + exit_code(3, __PRETTY_FUNCTION__, "missing nonce in reply"); + } + /* if qop is supported we need som additional header */ + if (qop_auth == 1) { + unsigned int cnonce; + snprintf(insert, QOP_STR_LEN+QOPAUTH_STR_LEN+3, "%s%s, ", QOP_STR, QOPAUTH_STR); + insert+=strlen(insert); + nonce_count++; + snprintf(insert, NC_STR_LEN+11, "%s%08x, ", NC_STR, nonce_count); + insert+=strlen(insert); + cnonce=(unsigned int)rand(); + snprintf(insert, 12+8, "cnonce=\"%x\", ", cnonce); + insert+=strlen(insert); + /* hopefully 100 is enough */ + qop_tmp=str_alloc(100); + snprintf(qop_tmp, 8+8+8, "%08x:%x:auth:", nonce_count, cnonce); + } + /* if no password is given we try it with empty password */ + if (!password) + password = EMPTY_STR; + + if (algo == SIPSAK_ALGO_MD5) { + if (authhash) { + strncpy((char*)&ha1_hex[0], authhash, SIPSAK_HASHHEXLEN_MD5); + } + else { + MD5Init(&Md5Ctx); + MD5Update(&Md5Ctx, usern, (unsigned int)strlen(usern)); + MD5Update(&Md5Ctx, ":", 1); + MD5Update(&Md5Ctx, realm, (unsigned int)strlen(realm)); + MD5Update(&Md5Ctx, ":", 1); + MD5Update(&Md5Ctx, password, (unsigned int)strlen(password)); + MD5Final(&ha1[0], &Md5Ctx); + cvt_hex(&ha1[0], &ha1_hex[0], SIPSAK_HASHLEN_MD5); + } + + MD5Init(&Md5Ctx); + MD5Update(&Md5Ctx, method, (unsigned int)strlen(method)); + MD5Update(&Md5Ctx, ":", 1); + MD5Update(&Md5Ctx, uri, (unsigned int)strlen(uri)); + MD5Final(&ha2[0], &Md5Ctx); + cvt_hex(&ha2[0], &ha2_hex[0], SIPSAK_HASHLEN_MD5); + + MD5Init(&Md5Ctx); + MD5Update(&Md5Ctx, &ha1_hex, SIPSAK_HASHHEXLEN_MD5); + MD5Update(&Md5Ctx, ":", 1); + MD5Update(&Md5Ctx, nonce, (unsigned int)strlen(nonce)); + MD5Update(&Md5Ctx, ":", 1); + if (qop_auth == 1) { + MD5Update(&Md5Ctx, qop_tmp, (unsigned int)strlen(qop_tmp)); + } + MD5Update(&Md5Ctx, &ha2_hex, SIPSAK_HASHHEXLEN_MD5); + MD5Final(&resp[0], &Md5Ctx); + cvt_hex(&resp[0], &resp_hex[0], SIPSAK_HASHLEN_MD5); + } +#ifdef HAVE_OPENSSL_SHA1 + else if (algo == SIPSAK_ALGO_SHA1) { + if (authhash) { + strncpy((char*)&ha1_hex[0], authhash, SIPSAK_HASHHEXLEN_SHA1); + } + else { + SHA1_Init(&Sha1Ctx); + SHA1_Update(&Sha1Ctx, usern, (unsigned int)strlen(usern)); + SHA1_Update(&Sha1Ctx, ":", 1); + SHA1_Update(&Sha1Ctx, realm, (unsigned int)strlen(realm)); + SHA1_Update(&Sha1Ctx, ":", 1); + SHA1_Update(&Sha1Ctx, password, (unsigned int)strlen(password)); + SHA1_Final(&ha1[0], &Sha1Ctx); + cvt_hex(&ha1[0], &ha1_hex[0], SIPSAK_HASHLEN_SHA1); + } + + SHA1_Init(&Sha1Ctx); + SHA1_Update(&Sha1Ctx, method, (unsigned int)strlen(method)); + SHA1_Update(&Sha1Ctx, ":", 1); + SHA1_Update(&Sha1Ctx, uri, (unsigned int)strlen(uri)); + SHA1_Final(&ha2[0], &Sha1Ctx); + cvt_hex(&ha2[0], &ha2_hex[0], SIPSAK_HASHLEN_SHA1); + + SHA1_Init(&Sha1Ctx); + SHA1_Update(&Sha1Ctx, &ha1_hex, SIPSAK_HASHHEXLEN_SHA1); + SHA1_Update(&Sha1Ctx, ":", 1); + SHA1_Update(&Sha1Ctx, nonce, (unsigned int)strlen(nonce)); + SHA1_Update(&Sha1Ctx, ":", 1); + if (qop_auth == 1) { + SHA1_Update(&Sha1Ctx, qop_tmp, (unsigned int)strlen(qop_tmp)); + } + SHA1_Update(&Sha1Ctx, &ha2_hex, SIPSAK_HASHHEXLEN_SHA1); + SHA1_Final(&resp[0], &Sha1Ctx); + cvt_hex(&resp[0], &resp_hex[0], SIPSAK_HASHLEN_SHA1); + } + else if (algo == SIPSAK_ALGO_SHA256) { + if (authhash) { + strncpy((char*)&ha1_hex[0], authhash, SIPSAK_HASHHEXLEN_SHA256); + } + else { + SHA256_Init(&Sha256Ctx); + SHA256_Update(&Sha256Ctx, usern, (unsigned int)strlen(usern)); + SHA256_Update(&Sha256Ctx, ":", 1); + SHA256_Update(&Sha256Ctx, realm, (unsigned int)strlen(realm)); + SHA256_Update(&Sha256Ctx, ":", 1); + SHA256_Update(&Sha256Ctx, password, (unsigned int)strlen(password)); + SHA256_Final(&ha1[0], &Sha256Ctx); + cvt_hex(&ha1[0], &ha1_hex[0], SIPSAK_HASHLEN_SHA256); + } + + SHA256_Init(&Sha256Ctx); + SHA256_Update(&Sha256Ctx, method, (unsigned int)strlen(method)); + SHA256_Update(&Sha256Ctx, ":", 1); + SHA256_Update(&Sha256Ctx, uri, (unsigned int)strlen(uri)); + SHA256_Final(&ha2[0], &Sha256Ctx); + cvt_hex(&ha2[0], &ha2_hex[0], SIPSAK_HASHLEN_SHA256); + + SHA256_Init(&Sha256Ctx); + SHA256_Update(&Sha256Ctx, &ha1_hex, SIPSAK_HASHHEXLEN_SHA256); + SHA256_Update(&Sha256Ctx, ":", 1); + SHA256_Update(&Sha256Ctx, nonce, (unsigned int)strlen(nonce)); + SHA256_Update(&Sha256Ctx, ":", 1); + if (qop_auth == 1) { + SHA256_Update(&Sha256Ctx, qop_tmp, (unsigned int)strlen(qop_tmp)); + } + SHA256_Update(&Sha256Ctx, &ha2_hex, SIPSAK_HASHHEXLEN_SHA256); + SHA256_Final(&resp[0], &Sha256Ctx); + cvt_hex(&resp[0], &resp_hex[0], SIPSAK_HASHLEN_SHA256); + } +#endif + + snprintf(insert, RESPONSE_STR_LEN+1, RESPONSE_STR); + insert+=RESPONSE_STR_LEN; + snprintf(insert, sizeof(resp_hex) + 8,"\"%s\"\r\n", &resp_hex[0]); + insert+=strlen(insert); + /* the auth header is complete, reinsert the rest of the request */ + strncpy(insert, backup, strlen(backup)); + } + else { + fprintf(stderr, "%s\nerror: couldn't find Proxy- or WWW-Authentication header" + " in the 401 response above\n", authreq); + exit_code(3, __PRETTY_FUNCTION__, "missing authentication header in reply"); + } + if (verbose>1) + printf("authorizing\n"); + /* hopefully we free all here */ + free(backup); + free(auth); + free(method); + free(uri); + free(realm); + free(nonce); + if (auth_username == NULL) free(usern); + if (qop_auth == 1) free(qop_tmp); +} + diff -Nru sipsak-0.9.6+git20170713/src/auth.h sipsak-0.9.7/src/auth.h --- sipsak-0.9.6+git20170713/src/auth.h 1970-01-01 00:00:00.000000000 +0000 +++ sipsak-0.9.7/src/auth.h 2019-04-27 04:54:34.000000000 +0000 @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2002-2004 Fhg Fokus + * Copyright (C) 2004-2005 Nils Ohlmeier + * + * This file belongs to sipsak, a free sip testing tool. + * + * sipsak is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * sipsak is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef SIPSAK_AUTH_H +#define SIPSAK_AUTH_H + +void insert_auth(char *message, char *authreq); + +#endif diff -Nru sipsak-0.9.6+git20170713/src/exit_code.c sipsak-0.9.7/src/exit_code.c --- sipsak-0.9.6+git20170713/src/exit_code.c 1970-01-01 00:00:00.000000000 +0000 +++ sipsak-0.9.7/src/exit_code.c 2019-04-27 04:54:34.000000000 +0000 @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2002-2004 Fhg Fokus + * Copyright (C) 2004-2005 Nils Ohlmeier + * + * This file belongs to sipsak, a free sip testing tool. + * + * sipsak is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * sipsak is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sipsak.h" + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STDIO_H +# include +#endif +#ifdef HAVE_STDLIB_H +# include +#endif +#ifdef HAVE_SYSLOG_H +# include +#endif + +#include "exit_code.h" + +enum exit_modes exit_mode = EM_DEFAULT; + +void log_message(const char *message) { + if ((sysl > 3) && (message != NULL)) { +#ifdef HAVE_SYSLOG + syslog(LOG_INFO, "%s", message); +#endif + } +} + +void exit_code(int code, const char *function, const char *reason) +{ +#ifdef WITH_TLS_TRANSP + if (transport == SIP_TLS_TRANSPORT) { +# ifdef USE_GNUTLS + if (tls_session) { + gnutls_deinit(tls_session); + } + if (xcred) { + gnutls_certificate_free_credentials(xcred); + } + gnutls_global_deinit(); +# else /* USE_GNUTLS */ +# ifdef USE_OPENSSL +# endif /* USE_OPENSSL */ +# endif /* USE_GNUTLS */ + } +#endif /* WITH_TLS_TRANSP */ + + if ((sysl > 0) && (reason != NULL)) { +#ifdef HAVE_SYSLOG + syslog(LOG_INFO, "%s: %s", function, reason); + closelog(); +#endif + } + + switch(exit_mode) { + case EM_DEFAULT: + if (code == 4) { + exit(0); + } else { + exit(code); + } + case EM_NAGIOS: + if (code == 0) { + printf("SIP ok\n"); + exit(0); + } else if (code == 4) { + printf("SIP warning\n"); + exit(1); + } else { + printf("SIP failure\n"); + exit(2); + } + default: + fprintf(stderr, "ERROR: unknown exit code\n"); + exit(1); + } +} diff -Nru sipsak-0.9.6+git20170713/src/exit_code.h sipsak-0.9.7/src/exit_code.h --- sipsak-0.9.6+git20170713/src/exit_code.h 1970-01-01 00:00:00.000000000 +0000 +++ sipsak-0.9.7/src/exit_code.h 2019-04-27 04:54:34.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2002-2004 Fhg Fokus + * Copyright (C) 2004-2005 Nils Ohlmeier + * + * This file belongs to sipsak, a free sip testing tool. + * + * sipsak is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * sipsak is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef SIPSAK_EXITCODE_H +#define SIPSAK_EXITCODE_H + +enum exit_modes { EM_DEFAULT, EM_NAGIOS }; + +extern enum exit_modes exit_mode; + +void log_message(const char *message); + +void exit_code(int code, const char *function, const char *reason); + +#endif diff -Nru sipsak-0.9.6+git20170713/src/header_f.c sipsak-0.9.7/src/header_f.c --- sipsak-0.9.6+git20170713/src/header_f.c 1970-01-01 00:00:00.000000000 +0000 +++ sipsak-0.9.7/src/header_f.c 2019-04-27 04:54:34.000000000 +0000 @@ -0,0 +1,631 @@ +/* + * Copyright (C) 2002-2004 Fhg Fokus + * Copyright (C) 2004-2005 Nils Ohlmeier + * + * This file belongs to sipsak, a free sip testing tool. + * + * sipsak is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * sipsak is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sipsak.h" + +#include "header_f.h" +#include "exit_code.h" +#include "helper.h" +#include "shoot.h" + + +/* add the given header(s) below the request line */ +void insert_header(char *mes, char *header, int first) { + char *ins, *backup; + + if (first) { + ins = strchr(mes, '\n'); + if (ins == NULL) { + printf("failed to find a new line in the message\n"); + exit_code(2, __PRETTY_FUNCTION__, "failed to find a new line in the message"); + } + ins++; + } + else { + ins = mes; + } + backup = str_alloc(strlen(ins) + 1); + strncpy(backup, ins, strlen(ins)); + strncpy(ins, header, strlen(header)); + strncpy(ins + strlen(header), backup, strlen(backup)+1); + free(backup); +} + +/* add a Via Header Field in the message. */ +void add_via(char *mes) +{ + char *via_line, *via, *backup; + + if ((via=STRCASESTR(mes, VIA_STR)) == NULL && + (via=STRCASESTR(mes, VIA_SHORT_STR)) == NULL) { + /* We didn't found a Via so we insert our via + direct after the first line. */ + via=strchr(mes,'\n'); + if(via == NULL) { + fprintf(stderr, "error: failed to find a position to insert Via:\n" + "'%s'\n", mes); + exit_code(2, __PRETTY_FUNCTION__, "failed to find position to insert to insert Via header"); + } + via++; + } + if (*via == '\n') + via++; + /* build our own Via-header-line */ + via_line = str_alloc(VIA_SIP_STR_LEN+TRANSPORT_STR_LEN+1+ + strlen(fqdn)+15+30+1); + snprintf(via_line, + VIA_SIP_STR_LEN+TRANSPORT_STR_LEN+1+strlen(fqdn)+15+30, + "%s%s %s:%i;branch=z9hG4bK.%08x;rport;alias\r\n", + VIA_SIP_STR, transport_str, fqdn, lport, rand()); + if (verbose > 2) + printf("our Via-Line: %s\n", via_line); + + if (strlen(mes)+strlen(via_line)>= BUFSIZE){ + printf("can't add our Via Header Line because file is too big\n"); + exit_code(2, __PRETTY_FUNCTION__, "Via header to big for buffer"); + } + /* finnaly make a backup, insert our via and append the backup */ + backup=str_alloc((strlen(via)+1)); + strncpy(backup, via, strlen(via)); + strncpy(via, via_line, strlen(via_line)); + strncpy(via+strlen(via_line), backup, strlen(backup)+1); + if (verbose > 2) + printf("New message with Via-Line:\n%s\n", mes); + free(via_line); + free(backup); +} + +/* copy the via lines from the message to the message + reply for correct routing of our reply. +*/ +void cpy_vias(char *reply, char *dest){ + char *first_via, *middle_via, *last_via, *backup; + + /* lets see if we find any via */ + if ((first_via=STRCASESTR(reply, VIA_STR))==NULL && + (first_via=STRCASESTR(reply, VIA_SHORT_STR))==NULL ){ + fprintf(stderr, "error: the received message doesn't contain a Via header\n"); + exit_code(3, __PRETTY_FUNCTION__, "missing Via header in message"); + } + last_via=first_via+4; + /* proceed additional via lines */ + while ((middle_via=STRCASESTR(last_via, VIA_STR))!=NULL || + (middle_via=STRCASESTR(last_via, VIA_SHORT_STR))!=NULL ) + last_via=middle_via+4; + last_via=strchr(last_via, '\n'); + middle_via=strchr(dest, '\n')+1; + if (middle_via == NULL) { + fprintf(stderr, "error: failed to locate end of middle Via header\n"); + exit_code(3, __PRETTY_FUNCTION__, "missing end of Via header in message"); + } + /* make a backup, insert the vias after the first line and append + backup + */ + backup=str_alloc(strlen(middle_via)+1); + strcpy(backup, middle_via); + strncpy(middle_via, first_via, (size_t)(last_via-first_via+1)); + strcpy(middle_via+(last_via-first_via+1), backup); + free(backup); + if (verbose > 2) + printf("message reply with vias included:\n%s\n", dest); +} + +void cpy_to(char *reply, char *dest) { + char *src_to, *dst_to, *backup, *tmp; + + /* find the position where we want to insert the To */ + if ((dst_to=STRCASESTR(dest, TO_STR))==NULL && + (dst_to=STRCASESTR(dest, TO_SHORT_STR))==NULL) { + fprintf(stderr, "error: could not find To in the destination: %s\n", dest); + exit_code(2, __PRETTY_FUNCTION__, "missing To header in target buffer"); + } + if (*dst_to == '\n') + dst_to++; + /* find the To we want to copy */ + if ((src_to=STRCASESTR(reply, TO_STR))==NULL && + (src_to=STRCASESTR(reply, TO_SHORT_STR))==NULL) { + if (verbose > 0) + fprintf(stderr, "warning: could not find To in reply. " + "trying with original To\n"); + } + else { + if (*src_to == '\n') + src_to++; + /* both To found, so copy it */ + tmp=strchr(dst_to, '\n'); + tmp++; + backup=str_alloc(strlen(tmp)+1); + strcpy(backup, tmp); + tmp=strchr(src_to, '\n'); + strncpy(dst_to, src_to, (size_t)(tmp-src_to+1)); + strcpy(dst_to+(tmp-src_to+1), backup); + free(backup); + if (verbose >2) + printf("reply with copyed To:\n%s\n", dest); + } +} + +/* check for the existence of a Max-Forwards header field. if its + present it sets it to the given value, if not it will be inserted.*/ +void set_maxforw(char *mes, int value){ + char *max, *backup, *crlfi; + int maxforward; + + if ((max=STRCASESTR(mes, MAX_FRW_STR))==NULL){ + /* no max-forwards found so insert it after the first line*/ + max=strchr(mes,'\n'); + if (!max) { + printf("failed to find newline\n"); + exit_code(254, __PRETTY_FUNCTION__, "missing newline in buffer"); + } + max++; + backup=str_alloc(strlen(max)+1); + strncpy(backup, max, (size_t)(strlen(max))); + if (value == -1) { + maxforward = 70; // RFC3261 default + } + else { + maxforward = value; + } + snprintf(max, MAX_FRW_STR_LEN+6, "%s%i\r\n", MAX_FRW_STR, maxforward); + max=strchr(max,'\n'); + max++; + strncpy(max, backup, strlen(backup)+1); + free(backup); + if (verbose > 1) + printf("Max-Forwards %i inserted into header\n", maxforward); + if (verbose > 2) + printf("New message with inserted Max-Forwards:\n%s\n", mes); + } + else{ + /* found max-forwards => overwrite the value with maxforw*/ + crlfi=strchr(max,'\n'); + crlfi++; + backup=str_alloc(strlen(crlfi)+1); + strncpy(backup, crlfi, strlen(crlfi)); + crlfi=max + MAX_FRW_STR_LEN; + if (value == -1) { + maxforward = str_to_int(1, crlfi); + maxforward++; + } + else { + maxforward = value; + } + snprintf(crlfi, 6, "%i\r\n", maxforward); + crlfi=strchr(max,'\n'); + crlfi++; + strncpy(crlfi, backup, strlen(backup)+1); + free(backup); + if (verbose > 1) + printf("Max-Forwards set to %i\n", maxforward); + if (verbose > 2) + printf("New message with changed Max-Forwards:\n%s\n", mes); + } +} + +/* replaces the uri in first line of mes with the other uri */ +void uri_replace(char *mes, char *uri) +{ + char *foo, *backup; + + foo=strchr(mes, '\n'); + if (!foo) { + printf("failed to find newline\n"); + exit_code(254, __PRETTY_FUNCTION__, "missing newline in buffer"); + } + foo++; + backup=str_alloc(strlen(foo)+1); + strncpy(backup, foo, strlen(foo)); + foo=STRCASESTR(mes, "sip"); + strncpy(foo, uri, strlen(uri)); + strncpy(foo+strlen(uri), SIP20_STR, SIP20_STR_LEN); + strncpy(foo+strlen(uri)+SIP20_STR_LEN, backup, strlen(backup)+1); + free(backup); + if (verbose > 2) + printf("Message with modified uri:\n%s\n", mes); +} + +/* replace the Content-Length value with the given value */ +void set_cl(char* mes, int contentlen) { + char *cl, *cr, *backup; + + if ((cl=STRCASESTR(mes, CON_LEN_STR)) == NULL && + (cl=STRCASESTR(mes, CON_LEN_SHORT_STR)) == NULL) { + printf("missing Content-Length in message\n"); + return; + } + if (*cl == '\n') { + cl++; + } + cr = strchr(cl, '\n'); + cr++; + backup=str_alloc(strlen(cr)+1); + strncpy(backup, cr, strlen(cr)); + if (*cl == 'C') + cr=cl + CON_LEN_STR_LEN; + else + cr=cl + 3; + snprintf(cr, 6, "%i\r\n", contentlen); + cr=strchr(cr, '\n'); + cr++; + strncpy(cr, backup, strlen(backup)+1); + free(backup); + if (verbose > 2) { + printf("Content-Length set to %i\n" + "New message with changed Content-Length:\n%s\n", contentlen, mes); + } +} + +/* returns the content length from the message; in case of error it + * return -1 */ +int get_cl(char* mes) { + char *cl; + + if ((cl=STRCASESTR(mes, CON_LEN_STR)) == NULL && + (cl=STRCASESTR(mes, CON_LEN_SHORT_STR)) == NULL) { + if (verbose > 1) + printf("missing Content-Length in message\n"); + return -1; + } + if (*cl == '\n') { + cl+=3; + } + else { + cl+=15; + } + return str_to_int(1, cl); +} + +/* returns 1 if the rr_line contains the lr parameter + * otherwise 0 */ +int find_lr_parameter(char *rr_line) { + char *eol, *lr; + + eol = strchr(rr_line, '\n'); + lr = STRCASESTR(rr_line, ";lr"); + if ((eol == NULL) || (lr == NULL) || (lr > eol)) { + return 0; + } + else { + return 1; + } +} + +/* copies the Record-Route header from src to dst. + * if route is set Record-Route will be replaced by Route */ +void cpy_rr(char* src, char *dst, int route) { + char *rr, *cr, *cr2, *backup; + int len; + + cr = strchr(dst, '\n'); + if (cr == NULL) { + fprintf(stderr, "error: failed to find newline in destination\n"); + exit_code(3, __PRETTY_FUNCTION__, "missing newline in target buffer"); + } + cr++; + rr = STRCASESTR(src, RR_STR); + if (rr != NULL) { + if (find_lr_parameter(rr) == 0) { + fprintf(stderr, "error: strict routing is not support yet\n"); + exit_code(252, __PRETTY_FUNCTION__, "strict routing is not supported"); + } + backup=str_alloc(strlen(cr)+1); + strncpy(backup, cr, strlen(cr)); + if (route == 0) + len = RR_STR_LEN; + else + len = ROUTE_STR_LEN; + while (rr != NULL) { + if (route == 0) { + strncpy(cr, RR_STR, RR_STR_LEN); + } + else { + strncpy(cr, ROUTE_STR, ROUTE_STR_LEN); + } + cr += len; + cr2 = strchr(rr, '\n'); + if (cr2 == NULL) { + fprintf(stderr, "error: failed to find end of line\n"); + exit_code(3, __PRETTY_FUNCTION__, "missing newline in buffer"); + } + strncpy(cr, rr + RR_STR_LEN, (cr2 - (rr + len) + 1)); + cr+=(cr2 - (rr + RR_STR_LEN) + 1); + rr = STRCASESTR(++rr, RR_STR); + } + strncpy(cr, backup, strlen(backup)+1); + free(backup); + if (verbose > 2) + printf("New message with inserted Route:\n%s\n", dst); + } +} + +/* build an ACK from the given invite and reply. + * NOTE: space has to be allocated already for the ACK */ +void build_ack(char *invite, char *reply, char *dest, + struct sipsak_regexp *reg) { + char *tmp; + int len; + + if ((tmp = STRCASESTR(invite, "\r\n\r\n")) != NULL) { + len = (tmp + 4) - invite; + } + else { + len = strlen(invite); + } + memcpy(dest, invite, len); + *(dest + len) = '\0'; + replace_string(dest, "INVITE", "ACK"); + set_cl(dest, 0); + cpy_to(reply, dest); + if (regexec(&(reg->okexp), reply, 0, 0, 0)==0) { + cpy_rr(reply, dest, 1); + /* 200 ACK must be in new transaction */ + new_branch(dest); + if((tmp = uri_from_contact(reply))!= NULL) { + uri_replace(dest, tmp); + free(tmp); + } + } +} + +/* tryes to find the warning header filed and prints out the IP */ +void warning_extract(char *message) +{ + char *warning, *end, *mid, *server; + int srvsize; + + if ((warning=STRCASESTR(message, "Warning:"))==NULL) { + if (verbose > 0) + printf("'no Warning header found' "); + else + printf("?? "); + return; + } + end=strchr(warning, '"'); + end--; + warning=strchr(warning, '3'); + warning+=4; + mid=strchr(warning, ':'); + if (mid) + end=mid; + srvsize=end - warning + 1; + server=str_alloc((size_t)srvsize); + server=strncpy(server, warning, (size_t)(srvsize - 1)); + printf("%s ", server); + free(server); +} + +/* tries to find and return the number in the CSeq header */ +int cseq(char *message) +{ + char *cseq; + int num; + + cseq=STRCASESTR(message, CSEQ_STR); + if (cseq) { + cseq+=6; + num=str_to_int(1, cseq); + if (num < 1) { + if (verbose > 2) + printf("CSeq found but not convertible\n"); + return 0; + } + return num; + } + if (verbose > 2) + printf("no CSeq found\n"); + return 0; +} + +/* if it find the Cseq number in the message it will increased by one */ +void increase_cseq(char *message, char *reply) +{ + int cs; + char *cs_s, *eol, *backup; + + cs = cseq(message); + if ((cs < 1) && (verbose > 1)) { + printf("CSeq increase failed because unable to extract CSeq number\n"); + return; + } + if (cs == INT_MAX) + cs = 1; + else + cs++; + cs_s=STRCASESTR(message, CSEQ_STR); + if (cs_s) { + cs_s+=6; + eol=strchr(cs_s, ' '); + eol++; + backup=str_alloc(strlen(eol)+1); + strncpy(backup, eol, (size_t)(strlen(eol))); + snprintf(cs_s, 11, "%i ", cs); + cs_s+=strlen(cs_s); + strncpy(cs_s, backup, strlen(backup)); + free(backup); + cseq_counter = cs; + } + else if (verbose > 1) + printf("'CSeq' not found in message\n"); + if (reply != NULL) { + cs_s=STRCASESTR(reply, CSEQ_STR); + if (cs_s) { + cs_s+=6; + eol=strchr(cs_s, ' '); + eol++; + backup=str_alloc(strlen(eol)+1); + strncpy(backup, eol, (size_t)(strlen(eol))); + snprintf(cs_s, 11, "%i ", cs); + cs_s+=strlen(cs_s); + strncpy(cs_s, backup, strlen(backup)); + free(backup); + } + else if (verbose > 1) + printf("'CSeq' not found in reply\n"); + } +} + +/* separates the given URI into the parts by setting the pointer but it + destroyes the URI */ +void parse_uri(char *uri, char **scheme, char **user, char **host, int *port) +{ + char *col, *col2, *at; + col = col2 = at = NULL; + *port = 0; + *scheme = *user = *host = NULL; + if ((col=strchr(uri,':'))!=NULL) { + if ((at=strchr(uri,'@'))!=NULL) { + *col = '\0'; + *at = '\0'; + if (at > col) { + *scheme = uri; + *user = ++col; + *host = ++at; + if ((col2=strchr(*host,':'))!=NULL) { + *col2 = '\0'; + *port = str_to_int(1, ++col2); + } + } + else { + *user = uri; + *host = ++at; + *port = str_to_int(1, ++col); + } + } + else { + *col = '\0'; + col++; + if ((col2=strchr(col,':'))!=NULL) { + *col2 = '\0'; + *scheme = uri; + *host = col; + *port = str_to_int(1, ++col2); + } + else { + if (is_number(col)) { + *host = uri; + *port = str_to_int(1, col); + } + else { + *scheme = uri; + *host = col; + } + } + } + } + else { + *host = uri; + } +} + +/* return a copy of the URI from the Contact of the message if found */ +char* uri_from_contact(char *message) +{ + char *contact, *end, *tmp, c; + + /* try to find the contact in the redirect */ + if ((contact=STRCASESTR(message, CONT_STR))==NULL && + (contact=STRCASESTR(message, CONT_SHORT_STR))==NULL ) { + if(verbose > 1) + printf("'Contact' not found in the message\n"); + return NULL; + } + if (*contact == '\n') + contact++; + + if((end=strchr(contact,'\r'))!=NULL) { + c = '\r'; + *end = '\0'; + } + else if((end=strchr(contact,'\n'))!=NULL) { + c = '\n'; + *end = '\0'; + } + else { + c = '\0'; + end = contact + strlen(contact); + } + + tmp = NULL; + + if ((contact=STRCASESTR(contact, "sip:"))!=NULL) { + if ((tmp=strchr(contact+4, ';'))!=NULL) { + *end = c; + end = tmp; + c = *end; + *end = '\0'; + } + if ((tmp=strchr(contact+4, '>'))!=NULL) { + *end = c; + end = tmp; + c = *end; + *end = '\0'; + } + tmp = str_alloc(strlen(contact)+1); + memcpy(tmp,contact,strlen(contact)); + } + + *end = c; + + return tmp; +} + +/* replace the 8 bytes behind the first magic cookie with a new + * random value */ +void new_branch(char *message) +{ + char *branch; + char backup; + + if((branch = STRCASESTR(message,"branch=z9hG4bK.")) != NULL) { + backup = *(branch+15+8); + snprintf(branch+15, 9, "%08x", rand()); + *(branch+15+8) = backup; + } +} + +/* increase the CSeq and insert a new branch value */ +void new_transaction(char *message, char *reply) +{ + increase_cseq(message, reply); + new_branch(message); +} + +/* just print the first line of the message */ +void print_message_line(char *message) +{ + char *crlf; + + crlf=strchr(message, '\n'); + if (!crlf) { + printf("failed to find newline\n"); + exit_code(254, __PRETTY_FUNCTION__, "missing newline in buffer"); + } + else if (*(crlf - 1) == '\r') + crlf--; + printf("%.*s\n", (int)(crlf - message), message); +} + +/* return pointer to the beginning of the message body */ +char* get_body(char *mes) { + char *cr; + + if ((cr = strstr(mes, "\r\n\r\n")) != NULL) { + cr+=4; + } + return cr; +} diff -Nru sipsak-0.9.6+git20170713/src/header_f.h sipsak-0.9.7/src/header_f.h --- sipsak-0.9.6+git20170713/src/header_f.h 1970-01-01 00:00:00.000000000 +0000 +++ sipsak-0.9.7/src/header_f.h 2019-04-27 04:54:34.000000000 +0000 @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2002-2004 Fhg Fokus + * Copyright (C) 2004-2005 Nils Ohlmeier + * + * This file belongs to sipsak, a free sip testing tool. + * + * sipsak is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * sipsak is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef SIPSAK_HEADER_H +#define SIPSAK_HEADER_H + +#include "shoot.h" + +void insert_header(char *mes, char *header, int first); + +void add_via(char *mes); + +void cpy_vias(char *reply, char *dest); + +void cpy_to(char *reply, char *dest); + +void set_maxforw(char *mes, int value); + +void uri_replace(char *mes, char *uri); + +void set_cl(char* mes, int contentlen); + +int get_cl(char* mes); + +int find_lr_parameter(char *rr_line); + +void cpy_rr(char* src, char *dst, int route); + +void build_ack(char *invite, char *reply, char *dest, + struct sipsak_regexp *reg); + +void warning_extract(char *message); + +int cseq(char *message); + +void increase_cseq(char *message, char *reply); + +void parse_uri(char *uri, char **scheme, char **user, char **host, int *port); + +char* uri_from_contact(char *message); + +void new_branch(char *message); + +void new_transaction(char *message, char *reply); + +void print_message_line(char *message); + +char* get_body(char *mes); +#endif diff -Nru sipsak-0.9.6+git20170713/src/helper.c sipsak-0.9.7/src/helper.c --- sipsak-0.9.6+git20170713/src/helper.c 1970-01-01 00:00:00.000000000 +0000 +++ sipsak-0.9.7/src/helper.c 2019-04-27 04:54:34.000000000 +0000 @@ -0,0 +1,869 @@ +/* + * Copyright (C) 2002-2004 Fhg Fokus + * Copyright (C) 2004-2005 Nils Ohlmeier + * + * This file belongs to sipsak, a free sip testing tool. + * + * sipsak is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * sipsak is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "sipsak.h" + +#ifdef HAVE_STDARG_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_UNISTD_H +# ifdef HAVE_SYS_TYPES_H +# include +# endif +# include +#endif +#ifdef HAVE_SYS_UTSNAME_H +# include +#endif +#ifdef HAVE_CTYPE_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_RULI_H +# include +#endif +#ifdef HAVE_ERRNO_H +# include +#endif +#ifdef HAVE_CARES_H +# ifdef HAVE_ARPA_NAMESER_H +# include +# endif +# include +# ifndef NS_RRFIXEDSZ +# define NS_RRFIXEDSZ 10 +# define NS_QFIXEDSZ 4 +# define NS_HFIXEDSZ 12 +# endif + int caport; + unsigned long caadr; + char *ca_tmpname; + ares_channel channel; + +#endif // HAVE_CARES_H + +#include "helper.h" +#include "exit_code.h" + +/* returns 1 if the string an IP address otherwise zero */ +int is_ip(char *str) { + int i = 0; + int dotcount = 0; + + /*try understanding if this is a valid ip address + we are skipping the values of the octets specified here. + for instance, this code will allow 952.0.320.567 through*/ + while (*str != '\0') + { + for (i = 0; i < 3; i++, str++) + if (isdigit((int)*str) == 0) + break; + if (*str != '.') + break; + str++; + dotcount++; + } + + /* three dots with up to three digits in before, between and after ? */ + if (*str == '\0' && dotcount == 3 && i > 0 && i <= 3) + return 1; + else + return 0; +} + +/* take either a dot.decimal string of ip address or a +domain name and returns a NETWORK ordered long int containing +the address. i chose to internally represent the address as long for speedier +comparisons. + +any changes to getaddress have to be patched back to the net library. +contact: farhan@hotfoon.com + + returns zero if there is an error. + this is convenient as 0 means 'this' host and the traffic of + a badly behaving dns system remains inside (you send to 0.0.0.0) +*/ + +unsigned long getaddress(char *host) { + struct hostent* pent; + long addr; + + if (strlen(host) == 0) { + return 0; + } + if (is_ip(host)) { + return inet_addr(host); + } + + /* try the system's own resolution mechanism for dns lookup: + required only for domain names. + in spite of what the rfc2543 :D Using SRV DNS Records recommends, + we are leaving it to the operating system to do the name caching. + + this is an important implementational issue especially in the light + dynamic dns servers like dynip.com or dyndns.com where a dial + ip address is dynamically assigned a sub domain like farhan.dynip.com + + although expensive, this is a must to allow OS to take + the decision to expire the DNS records as it deems fit. + */ + pent = gethostbyname(host); + if (!pent) { + printf("'%s' is unresolveable\n", host); + exit_code(2, __PRETTY_FUNCTION__, "hostname is not resolveable"); + } + addr = *(uint32_t *) (pent->h_addr); + return addr; +} + +#ifdef HAVE_CARES_H +static const unsigned char *parse_rr(const unsigned char *aptr, const unsigned char *abuf, int alen) { + char *name; + long len; + int status, type, dnsclass, dlen; + struct in_addr addr; + + if (aptr == NULL) { + return NULL; + } + dbg("ca_tmpname: %s\n", ca_tmpname); + status = ares_expand_name(aptr, abuf, alen, &name, &len); + if (status != ARES_SUCCESS) { + printf("error: failed to expand query name\n"); + exit_code(2, __PRETTY_FUNCTION__, "failed to expand query name"); + } + aptr += len; + if (aptr + NS_RRFIXEDSZ > abuf + alen) { + printf("error: not enough data in DNS answer 1\n"); + free(name); + return NULL; + } + type = DNS_RR_TYPE(aptr); + dnsclass = DNS_RR_CLASS(aptr); + dlen = DNS_RR_LEN(aptr); + aptr += NS_RRFIXEDSZ; + if (aptr + dlen > abuf + alen) { + printf("error: not enough data in DNS answer 2\n"); + free(name); + return NULL; + } + if (dnsclass != CARES_CLASS_C_IN) { + printf("error: unsupported dnsclass (%i) in DNS answer\n", dnsclass); + free(name); + return NULL; + } + if (type != CARES_TYPE_SRV && type != CARES_TYPE_A && type != CARES_TYPE_CNAME) { + printf("error: unsupported DNS response type (%i)\n", type); + free(name); + return NULL; + } + if (type == CARES_TYPE_SRV) { + free(name); + caport = DNS__16BIT(aptr + 4); + dbg("caport: %i\n", caport); + status = ares_expand_name(aptr + 6, abuf, alen, &name, &len); + if (status != ARES_SUCCESS) { + printf("error: failed to expand SRV name\n"); + return NULL; + } + dbg("SRV name: %s\n", name); + if (is_ip(name)) { + caadr = inet_addr(name); + free(name); + } + else { + ca_tmpname = name; + } + } + else if (type == CARES_TYPE_CNAME) { + if ((ca_tmpname != NULL) && + (STRNCASECMP(ca_tmpname, name, strlen(ca_tmpname)) == 0)) { + ca_tmpname = malloc(strlen(name) + 1); + if (ca_tmpname == NULL) { + printf("error: failed to allocate memory\n"); + exit_code(2, __PRETTY_FUNCTION__, "memory allocation failure"); + } + strcpy(ca_tmpname, name); + free(name); + } + else { + free(name); + status = ares_expand_name(aptr, abuf, alen, &name, &len); + if (status != ARES_SUCCESS) { + printf("error: failed to expand CNAME\n"); + return NULL; + } + dbg("CNAME: %s\n", name); + if (is_ip(name)) { + caadr = inet_addr(name); + free(name); + } + else { + ca_tmpname = name; + } + } + } + else if (type == CARES_TYPE_A) { + if (dlen == 4 && STRNCASECMP(ca_tmpname, name, strlen(ca_tmpname)) == 0) { + memcpy(&addr, aptr, sizeof(struct in_addr)); + caadr = addr.s_addr; + } + free(name); + } + return aptr + dlen; +} + +static const unsigned char *skip_rr(const unsigned char *aptr, const unsigned char *abuf, int alen) { + int status, dlen; + long len; + char *name; + + if (aptr == NULL) { + return NULL; + } + dbg("skipping rr section...\n"); + status = ares_expand_name(aptr, abuf, alen, &name, &len); + if (status != ARES_SUCCESS) { + return NULL; + } + aptr += len; + dlen = DNS_RR_LEN(aptr); + aptr += NS_RRFIXEDSZ; + aptr += dlen; + free(name); + return aptr; +} + +static const unsigned char *skip_query(const unsigned char *aptr, const unsigned char *abuf, int alen) { + int status; + long len; + char *name; + + if (aptr == NULL) { + return NULL; + } + dbg("skipping query section...\n"); + status = ares_expand_name(aptr, abuf, alen, &name, &len); + if (status != ARES_SUCCESS) { + return NULL; + } + aptr += len; + aptr += NS_QFIXEDSZ; + free(name); + return aptr; +} + +static void cares_callback(void *arg, int status, int timeouts, unsigned char *abuf, int alen) { + int i; + unsigned int ancount, nscount, arcount; + const unsigned char *aptr; + + dbg("cares_callback: status=%i, alen=%i\n", status, alen); + if (status != ARES_SUCCESS) { + if (verbose > 1) + printf("ares failed: %s\n", ares_strerror(status)); + return; + } + + ancount = DNS_HEADER_ANCOUNT(abuf); + nscount = DNS_HEADER_NSCOUNT(abuf); + arcount = DNS_HEADER_ARCOUNT(abuf); + + dbg("ancount: %i, nscount: %i, arcount: %i\n", ancount, nscount, arcount); + + /* safety check */ + if (alen < NS_HFIXEDSZ) + return; + aptr = abuf + NS_HFIXEDSZ; + + aptr = skip_query(aptr, abuf, alen); + if (aptr == NULL) { + return; + } + + for (i = 0; i < ancount && caadr == 0 && aptr != NULL; i++) { + if (ca_tmpname == NULL) + aptr = parse_rr(aptr, abuf, alen); + else + aptr = skip_rr(aptr, abuf, alen); + } + if (caadr == 0 && aptr != NULL) { + for (i = 0; i < nscount && aptr != NULL; i++) { + aptr = skip_rr(aptr, abuf, alen); + } + for (i = 0; i < arcount && caadr == 0; i++) { + aptr = parse_rr(aptr, abuf, alen); + } + } +} + +static inline unsigned long srv_ares(char *host, int *port, char *srv) { + int nfds, count, srvh_len; + char *srvh; + fd_set read_fds, write_fds; + struct timeval *tvp, tv; + + caport = 0; + caadr = 0; + ca_tmpname = NULL; + dbg("starting ARES query\n"); + + srvh_len = strlen(host) + strlen(srv) + 2; + srvh = malloc(srvh_len); + if (srvh == NULL) { + printf("error: failed to allocate memory (%i) for ares query\n", srvh_len); + exit_code(2, __PRETTY_FUNCTION__, "memory allocation failure"); + } + memset(srvh, 0, srvh_len); + strncpy(srvh, srv, strlen(srv)); + memcpy(srvh + strlen(srv), ".", 1); + strcpy(srvh + strlen(srv) + 1, host); + dbg("hostname: '%s', len: %i\n", srvh, srvh_len); + + ares_query(channel, srvh, CARES_CLASS_C_IN, CARES_TYPE_SRV, cares_callback, (char *) NULL); + dbg("ares_query finished, waiting for result...\n"); + /* wait for query to complete */ + while (1) { + FD_ZERO(&read_fds); + FD_ZERO(&write_fds); + nfds = ares_fds(channel, &read_fds, &write_fds); + if (nfds == 0) + break; + tvp = ares_timeout(channel, NULL, &tv); + count = select(nfds, &read_fds, &write_fds, NULL, tvp); + if (count < 0 && errno != EINVAL) { + perror("ares select"); + exit_code(2, __PRETTY_FUNCTION__, "ares DNS resolution failure"); + } + ares_process(channel, &read_fds, &write_fds); + } + dbg("ARES answer processed\n"); + *port = caport; + if (caadr == 0 && ca_tmpname != NULL) { + caadr = getaddress(ca_tmpname); + } + if (ca_tmpname != NULL) + free(ca_tmpname); + free(srvh); + return caadr; +} +#endif // HAVE_CARES_H + +#ifdef HAVE_RULI_H +static inline unsigned long srv_ruli(char *host, int *port, char *srv) { + int srv_code; + int ruli_opts = RULI_RES_OPT_SEARCH | RULI_RES_OPT_SRV_NOINET6 | RULI_RES_OPT_SRV_NOSORT6 | RULI_RES_OPT_SRV_NOFALL; +#ifdef RULI_RES_OPT_SRV_CNAME + ruli_opts |= RULI_RES_OPT_SRV_CNAME; +#endif + + ruli_sync_t *sync_query = ruli_sync_query(srv, host, *port, ruli_opts); + + /* sync query failure? */ + if (!sync_query) { + printf("DNS SRV lookup failed for: %s\n", host); + exit_code(2, __PRETTY_FUNCTION__, "DNS SRV lookup failed"); + } + + srv_code = ruli_sync_srv_code(sync_query); + /* timeout? */ + if (srv_code == RULI_SRV_CODE_ALARM) { + printf("Timeout during DNS SRV lookup for: %s\n", host); + ruli_sync_delete(sync_query); + exit_code(2, __PRETTY_FUNCTION__, "timeout during DNS SRV lookup"); + } + /* service provided? */ + else if (srv_code == RULI_SRV_CODE_UNAVAILABLE) { + printf("SRV service not provided for: %s\n", host); + ruli_sync_delete(sync_query); + exit_code(2, __PRETTY_FUNCTION__, "missing service in DNS SRV reply"); + } + else if (srv_code) { + int rcode = ruli_sync_rcode(sync_query); + if (verbose > 1) + printf("SRV query failed for: %s, srv_code=%d, rcode=%d\n", host, srv_code, rcode); + ruli_sync_delete(sync_query); + return 0; + } + + ruli_list_t *srv_list = ruli_sync_srv_list(sync_query); + + int srv_list_size = ruli_list_size(srv_list); + + if (srv_list_size < 1) { + if (verbose > 1) + printf("No SRV record: %s.%s\n", srv, host); + return 0; + } + + ruli_srv_entry_t *entry = (ruli_srv_entry_t *) ruli_list_get(srv_list, 0); + ruli_list_t *addr_list = &entry->addr_list; + int addr_list_size = ruli_list_size(addr_list); + + if (addr_list_size < 1) { + printf("missing addresses in SRV lookup for: %s\n", host); + ruli_sync_delete(sync_query); + exit_code(2, __PRETTY_FUNCTION__, "missing address in DNS SRV reply"); + } + + *port = entry->port; + ruli_addr_t *addr = (ruli_addr_t *) ruli_list_get(addr_list, 0); + return addr->addr.ipv4.s_addr; +} +#endif // HAVE_RULI_H + +unsigned long getsrvaddress(char *host, int *port, char *srv) { +#ifdef HAVE_RULI_H + return srv_ruli(host, port, srv); +#else +# ifdef HAVE_CARES_H // HAVE_RULI_H + return srv_ares(host, port, srv); +# else // HAVE_CARES_H + return 0; +# endif +#endif +} + +/* Finds the SRV records for the given host. It returns the target IP + * address and fills the port and transport if a suitable SRV record + * exists. Otherwise it returns 0. The function follows 3263: first + * TLS, then TCP and finally UDP. */ +unsigned long getsrvadr(char *host, int *port, unsigned int *transport) { + unsigned long adr = 0; + +#ifdef HAVE_SRV + int srvport = 5060; + +#ifdef HAVE_CARES_H + int status; + int optmask = ARES_OPT_FLAGS; + struct ares_options options; + + options.flags = ARES_FLAG_NOCHECKRESP; + options.servers = NULL; + options.nservers = 0; + + status = ares_init_options(&channel, &options, optmask); + if (status != ARES_SUCCESS) { + printf("error: failed to initialize ares\n"); + exit_code(2, __PRETTY_FUNCTION__, "failed to init ares lib"); + } +#endif + +#ifdef WITH_TLS_TRANSP + adr = getsrvaddress(host, &srvport, SRV_SIP_TLS); + if (adr != 0) { + *transport = SIP_TLS_TRANSPORT; + if (verbose > 1) + printf("using SRV record: %s.%s:%i\n", SRV_SIP_TLS, host, srvport); + } + else { +#endif + adr = getsrvaddress(host, &srvport, SRV_SIP_TCP); + if (adr != 0) { + *transport = SIP_TCP_TRANSPORT; + if (verbose > 1) + printf("using SRV record: %s.%s:%i\n", SRV_SIP_TCP, host, srvport); + } + else { + adr = getsrvaddress(host, &srvport, SRV_SIP_UDP); + if (adr != 0) { + *transport = SIP_UDP_TRANSPORT; + if (verbose > 1) + printf("using SRV record: %s.%s:%i\n", SRV_SIP_UDP, host, srvport); + } + } +#ifdef WITH_TLS_TRANSP + } +#endif + +#ifdef HAVE_CARES_H + ares_destroy(channel); +#endif + + *port = srvport; +#endif // HAVE_SRV + return adr; +} + +/* because the full qualified domain name is needed by many other + functions it will be determined by this function. +*/ +void get_fqdn() { + char hname[100], dname[100], hlp[18]; + size_t namelen=100; + struct hostent* he; + struct utsname un; + + memset(&hname, 0, sizeof(hname)); + memset(&dname, 0, sizeof(dname)); + memset(&hlp, 0, sizeof(hlp)); + + if (hostname) { + strncpy(fqdn, hostname, FQDN_SIZE-1); + strncpy(hname, hostname, sizeof(hname)-1); + } + else { + if ((uname(&un))==0) { + strncpy(hname, un.nodename, sizeof(hname)-1); + } + else { + if (gethostname(&hname[0], namelen) < 0) { + fprintf(stderr, "error: cannot determine hostname\n"); + exit_code(2, __PRETTY_FUNCTION__, "failed to determine hostname"); + } + } +#ifdef HAVE_GETDOMAINNAME + /* a hostname with dots should be a domainname */ + if ((strchr(hname, '.'))==NULL) { + if (getdomainname(&dname[0], namelen) < 0) { + fprintf(stderr, "error: cannot determine domainname\n"); + exit_code(2, __PRETTY_FUNCTION__, "failed to get domainname"); + } + if (strcmp(&dname[0],"(none)")!=0) + snprintf(fqdn, FQDN_SIZE, "%s.%s", hname, dname); + } + else { + strncpy(fqdn, hname, FQDN_SIZE-1); + } +#endif + } + + if (!(numeric == 1 && is_ip(fqdn))) { + he=gethostbyname(hname); + if (he) { + if (numeric == 1) { + snprintf(hlp, sizeof(hlp), "%s", inet_ntoa(*(struct in_addr *) he->h_addr_list[0])); + strncpy(fqdn, hlp, FQDN_SIZE-1); + } + else { + if ((strchr(he->h_name, '.'))!=NULL && (strchr(hname, '.'))==NULL) { + strncpy(fqdn, he->h_name, FQDN_SIZE-1); + } + else { + strncpy(fqdn, hname, FQDN_SIZE-1); + } + } + } + else { + fprintf(stderr, "error: cannot resolve local hostname: %s\n", hname); + exit_code(2, __PRETTY_FUNCTION__, "failed to resolve local hostname"); + } + } + if ((strchr(fqdn, '.'))==NULL) { + if (hostname) { + fprintf(stderr, "warning: %s is not resolvable... continouing anyway\n", fqdn); + strncpy(fqdn, hostname, FQDN_SIZE-1); + } + else { + fprintf(stderr, "error: this FQDN or IP is not valid: %s\n", fqdn); + exit_code(2, __PRETTY_FUNCTION__, "invalid IP or FQDN"); + } + } + + if (verbose > 2) + printf("fqdnhostname: %s\n", fqdn); +} + +/* this function searches for search in mess and replaces it with + replacement */ +void replace_string(char *mess, char *search, char *replacement) { + char *backup, *insert; + + insert=STRCASESTR(mess, search); + if (insert==NULL){ + if (verbose > 2) + fprintf(stderr, "warning: could not find this '%s' replacement string in " + "message\n", search); + } + else { + while (insert){ + backup=str_alloc(strlen(insert)+1); + strcpy(backup, insert+strlen(search)); + strcpy(insert, replacement); + strcpy(insert+strlen(replacement), backup); + free(backup); + insert=STRCASESTR(mess, search); + } + } +} + +/* checks if the strings contains special double marks and then + * replace all occurrences of this strings in the message */ +void replace_strings(char *mes, char *strings) { + char *pos, *atr, *val, *repl, *end; + char sep; + + pos=atr=val=repl = NULL; + dbg("replace_strings entered\nstrings: '%s'\n", strings); + if ((isalnum(*strings) != 0) && + (isalnum(*(strings + strlen(strings) - 1)) != 0)) { + replace_string(request, "$replace$", replace_str); + } + else { + sep = *strings; + dbg("sep: '%c'\n", sep); + end = strings + strlen(strings); + pos = strings + 1; + while (pos < end) { + atr = pos; + pos = strchr(atr, sep); + if (pos != NULL) { + *pos = '\0'; + val = pos + 1; + pos = strchr(val, sep); + if (pos != NULL) { + *pos = '\0'; + pos++; + } + } + dbg("atr: '%s'\nval: '%s'\n", atr, val); + if ((atr != NULL) && (val != NULL)) { + repl = str_alloc(strlen(val) + 3); + if (repl == NULL) { + printf("failed to allocate memory\n"); + exit_code(2, __PRETTY_FUNCTION__, "memory allocation failure"); + } + sprintf(repl, "$%s$", atr); + replace_string(mes, repl, val); + free(repl); + } + dbg("pos: '%s'\n", pos); + } + } + dbg("mes:\n'%s'\n", mes); +} + +/* insert \r in front of all \n if it is not present already + * and and a trailing \r\n is not present */ +void insert_cr(char *mes) { + char *lf, *pos, *backup; + + pos = mes; + lf = strchr(pos, '\n'); + while ((lf != NULL) && (lf >= mes+1) && (*(--lf) != '\r')) { + backup=str_alloc(strlen(lf)+2); + strcpy(backup, lf+1); + *(lf+1) = '\r'; + strcpy(lf+2, backup); + free(backup); + pos = lf+3; + lf = strchr(pos, '\n'); + } + lf = STRCASESTR(mes, "\r\n\r\n"); + if (lf == NULL) { + lf = mes + strlen(mes); + sprintf(lf, "\r\n"); + } +} + +/* sipmly swappes the content of the two buffers */ +void swap_buffers(char *fst, char *snd) { + char *tmp; + + if (fst == snd) + return; + tmp = str_alloc(strlen(fst)+1); + strcpy(tmp, fst); + strcpy(fst, snd); + strcpy(snd, tmp); + free(tmp); +} + +void swap_ptr(char **fst, char **snd) { + char *tmp; + + tmp = *fst; + *fst = *snd; + *snd = tmp; +} + +/* trashes one character in buff randomly */ +void trash_random(char *message) { + int r; + float t; + char *position; + + t=(float)rand()/RAND_MAX; + r=(int)(t * (float)strlen(message)); + position=message+r; + r=(int)(t*(float)255); + *position=(char)r; + if (verbose > 2) + printf("request:\n%s\n", message); +} + +/* this function is taken from traceroute-1.4_p12 + which is distributed under the GPL and it returns + the difference between to timeval structs */ +double deltaT(struct timeval *t1p, struct timeval *t2p) { + register double dt; + + dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + + (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; + return (dt); +} + +/* returns one if the string contains only numbers otherwise zero */ +int is_number(char *number) { + int digit = 1; + if (strlen(number) == 0) { + return 0; + } + while (digit && (*number != '\0')) { + digit = isdigit(*number); + number++; + } + return digit ? 1 : 0; +} + +/* tries to convert the given string into an integer. it strips + * white-spaces and exits if an error happens */ +int str_to_int(int mode, char *num) { + int ret, len; + char *end, *start; + char *backup = NULL; + + len = strlen(num); + if (len == 0) { + fprintf(stderr, "error: string has zero length: '%s'\n", num); + ret = 2; + goto error; + } + /* we need to make a backup to insert the zero char */ + backup = malloc(len + 1); + if (!backup) { + fprintf(stderr, "error: failed to allocate memory\n"); + ret = 2; + goto error; + } + memcpy(backup, num, len + 1); + + start = backup; + end = backup + len; + while (isspace(*start) && (start < end)) { + start++; + } + if (start == end) { + fprintf(stderr, "error: string is too short: '%s'\n", num); + ret = 2; + goto error; + } + if (mode == 0) { + end--; + while (isspace(*end) && (end > start)) { + end--; + } + if (end != (backup + len - 1)) { + end++; + *end = '\0'; + } + } + else { + end = start; + end++; + while ((end < backup + len) && *end != '\0' && !isspace(*end)) { + end++; + } + *end = '\0'; + } + if (!is_number(start)) { + fprintf(stderr, "error: string is not a number: '%s'\n", start); + ret = 2; + goto error; + } + ret = atoi(start); + if (ret >= 0) { + free(backup); + return ret; + } + else { + fprintf(stderr, "error: failed to convert string to integer: '%s'\n", num); + ret = 2; + } +error: + if (backup) { + free(backup); + } + if (mode == 0) { + /* libcheck expects a return value not an exit code */ +#ifndef RUNNING_CHECK + exit_code(ret, __PRETTY_FUNCTION__, NULL); +#endif + } + return (ret * - 1); +} + +/* reads into the given buffer from standard input until the EOF + * character, LF character or the given size of the buffer is exceeded */ +int read_stdin(char *buf, int size, int ret) { + int i, j; + + for(i = 0; i < size - 1; i++) { + j = getchar(); + if (((ret == 0) && (j == EOF)) || + ((ret == 1) && (j == '\n'))) { + *(buf + i) = '\0'; + return i; + } + else { + *(buf + i) = j; + } + } + *(buf + i) = '\0'; + if (verbose) + fprintf(stderr, "warning: readin buffer size exceeded\n"); + return i; +} + +/* tries to allocate the given size of memory and sets it all to zero. + * if the allocation fails it exits */ +void *str_alloc(size_t size) { + char *ptr; +#ifdef HAVE_CALLOC + ptr = calloc(1, size); +#else + ptr = malloc(size); +#endif + if (ptr == NULL) { + fprintf(stderr, "error: memory allocation failed\n"); + exit_code(255, __PRETTY_FUNCTION__, "memory allocation failure"); + } +#ifndef HAVE_CALLOC + memset(ptr, 0, size); +#endif + return ptr; +} + +void dbg(char* format, ...) { +#ifdef DEBUG + va_list ap; + + fprintf(stderr, "DEBUG: "); + va_start(ap, format); + vfprintf(stderr, format, ap); + fflush(stderr); + va_end(ap); +#endif +} diff -Nru sipsak-0.9.6+git20170713/src/helper.h sipsak-0.9.7/src/helper.h --- sipsak-0.9.6+git20170713/src/helper.h 1970-01-01 00:00:00.000000000 +0000 +++ sipsak-0.9.7/src/helper.h 2019-04-27 04:54:34.000000000 +0000 @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2002-2004 Fhg Fokus + * Copyright (C) 2004-2005 Nils Ohlmeier + * + * This file belongs to sipsak, a free sip testing tool. + * + * sipsak is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * sipsak is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef SIPSAK_HELPER_H +#define SIPSAK_HELPER_H + +#include "sipsak.h" + +#ifdef HAVE_SYS_TIME_H +# include +#else +# include +#endif +#ifdef HAVE_SYS_SELECT_H +# include +#endif + +#ifdef HAVE_CARES_H +# define HAVE_SRV +#else +# ifdef HAVE_RULI_H +# define HAVE_SRV +# endif +#endif + +#ifdef HAVE_CARES_H +# define CARES_TYPE_A 1 +# define CARES_TYPE_CNAME 5 +# define CARES_TYPE_SRV 33 +# define CARES_CLASS_C_IN 1 +/* copied from ares_dns.h */ +# define DNS__16BIT(p) (((p)[0] << 8) | (p)[1]) +# define DNS_HEADER_ANCOUNT(h) DNS__16BIT((h) + 6) +# define DNS_HEADER_NSCOUNT(h) DNS__16BIT((h) + 8) +# define DNS_HEADER_ARCOUNT(h) DNS__16BIT((h) + 10) +# define DNS_RR_TYPE(r) DNS__16BIT(r) +# define DNS_RR_CLASS(r) DNS__16BIT((r) + 2) +# define DNS_RR_LEN(r) DNS__16BIT((r) + 8) +#endif + +#ifdef HAVE_SRV +# define SRV_SIP_TLS "_sip._tls" +# define SRV_SIP_TCP "_sip._tcp" +# define SRV_SIP_UDP "_sip._udp" +#endif + +int is_ip(char *str); + +unsigned long getaddress(char *host); + +unsigned long getsrvadr(char *host, int *port, unsigned int *transport); + +void get_fqdn(); + +void replace_string(char *mes, char *search, char *replacement); + +void replace_strings(char *mes, char *strings); + +void insert_cr(char *mes); + +void swap_buffers(char *fst, char *snd); + +void swap_ptr(char **fst, char **snd); + +void trash_random(char *message); + +double deltaT(struct timeval *t1p, struct timeval *t2p); + +int is_number(char *number); + +int str_to_int(int mode, char *num); + +int read_stdin(char *buf, int size, int ret); + +void *str_alloc(size_t size); + +void dbg(char* format, ...); +#endif diff -Nru sipsak-0.9.6+git20170713/src/md5.c sipsak-0.9.7/src/md5.c --- sipsak-0.9.6+git20170713/src/md5.c 1970-01-01 00:00:00.000000000 +0000 +++ sipsak-0.9.7/src/md5.c 2019-04-27 04:54:34.000000000 +0000 @@ -0,0 +1,362 @@ +/* + +MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + +Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "md5.h" + +#ifndef HAVE_EXTERNAL_MD5 + +#ifdef HAVE_STRING_H +# include +#endif + +#define USE_MEM + +/* Constants for MD5Transform routine. + */ + + + + +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64])); +static void Encode PROTO_LIST + ((unsigned char *, UINT4 *, unsigned int)); +static void Decode PROTO_LIST + ((UINT4 *, unsigned char *, unsigned int)); +static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int)); +static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int)); + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/* MD5 initialization. Begins an MD5 operation, writing a new context. + */ +void MD5Init (context) +MD5_CTX *context; /* context */ +{ + context->count[0] = context->count[1] = 0; + /* Load magic initialization constants. +*/ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. + */ +void MD5Update (context, input, inputLen) +MD5_CTX *context; /* context */ +unsigned char *input; /* input block */ +unsigned int inputLen; /* length of input block */ +{ + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((UINT4)inputLen << 3)) + + < ((UINT4)inputLen << 3)) + context->count[1]++; + context->count[1] += ((UINT4)inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible. +*/ + if (inputLen >= partLen) { + MD5_memcpy + ((POINTER)&context->buffer[index], (POINTER)input, partLen); + MD5Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + MD5_memcpy + ((POINTER)&context->buffer[index], (POINTER)&input[i], + inputLen-i); +} + +/* MD5 finalization. Ends an MD5 message-digest operation, writing the + the message digest and zeroizing the context. + */ +void MD5Final (digest, context) +unsigned char digest[16]; /* message digest */ +MD5_CTX *context; /* context */ +{ + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + Encode (bits, context->count, 8); + + /* Pad out to 56 mod 64. +*/ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update (context, PADDING, padLen); + + /* Append length (before padding) */ + MD5Update (context, bits, 8); + + /* Store state in digest */ + Encode (digest, context->state, 16); + + /* Zeroize sensitive information. +*/ + MD5_memset ((POINTER)context, 0, sizeof (*context)); +} + +/* MD5 basic transformation. Transforms state based on block. + */ +static void MD5Transform (state, block) +UINT4 state[4]; +unsigned char block[64]; +{ + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. +*/ + MD5_memset ((POINTER)x, 0, sizeof (x)); +} + +/* Encodes input (UINT4) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void Encode (output, input, len) +unsigned char *output; +UINT4 *input; +unsigned int len; +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (UINT4). Assumes len is + a multiple of 4. + */ +static void Decode (output, input, len) +UINT4 *output; +unsigned char *input; +unsigned int len; +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | + (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); +} + +/* Note: Replace "for loop" with standard memcpy if possible. + */ + +static void MD5_memcpy (output, input, len) +POINTER output; +POINTER input; +unsigned int len; +{ + +#ifndef USE_MEM + unsigned int i; + + for (i = 0; i < len; i++) + output[i] = input[i]; +#else + memcpy( output, input, len ); +#endif +} + +/* Note: Replace "for loop" with standard memset if possible. + */ +static void MD5_memset (output, value, len) +POINTER output; +int value; +unsigned int len; +{ + +#ifndef USE_MEM + unsigned int i; + for (i = 0; i < len; i++) + ((char *)output)[i] = (char)value; +#else + memset( output, value, len ); +#endif +} + +#endif /* ! HAVE_EXTERNAL_MD5 */ diff -Nru sipsak-0.9.6+git20170713/src/md5global.h sipsak-0.9.7/src/md5global.h --- sipsak-0.9.6+git20170713/src/md5global.h 1970-01-01 00:00:00.000000000 +0000 +++ sipsak-0.9.7/src/md5global.h 2019-04-27 04:54:34.000000000 +0000 @@ -0,0 +1,35 @@ +/* GLOBAL.H - RSAREF types and constants + * + */ + + +/* PROTOTYPES should be set to one if and only if the compiler supports + function argument prototyping. +The following makes PROTOTYPES default to 0 if it has not already + been defined with C compiler flags. + */ +#ifndef PROTOTYPES +#define PROTOTYPES 0 +#endif + +/* POINTER defines a generic pointer type */ +typedef unsigned char *POINTER; + +#ifdef HAVE_STDINT_H +# include +typedef uint32_t UINT4; +#else +/* UINT4 defines a four byte word */ +typedef unsigned long int UINT4; +#endif + +/* PROTO_LIST is defined depending on how PROTOTYPES is defined above. +If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it + returns an empty list. + */ +#if PROTOTYPES +#define PROTO_LIST(list) list +#else +#define PROTO_LIST(list) () +#endif + diff -Nru sipsak-0.9.6+git20170713/src/md5.h sipsak-0.9.7/src/md5.h --- sipsak-0.9.6+git20170713/src/md5.h 1970-01-01 00:00:00.000000000 +0000 +++ sipsak-0.9.7/src/md5.h 2019-04-27 04:54:34.000000000 +0000 @@ -0,0 +1,62 @@ +/* MD5.H - header file for MD5C.C + */ + + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +#ifndef SIPSAK_MD5_H +#define SIPSAK_MD5_H + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "sipsak.h" + +#ifdef HAVE_FULL_OPENSSL +# include +#endif + +#ifdef HAVE_EXTERNAL_MD5 + +# define MD5Init MD5_Init +# define MD5Update MD5_Update +# define MD5Final MD5_Final + +#else + +#include "md5global.h" + +/* MD5 context. */ +typedef struct { + UINT4 state[4]; /* state (ABCD) */ + UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} MD5_CTX; + +void MD5Init PROTO_LIST ((MD5_CTX *)); +void MD5Update PROTO_LIST + ((MD5_CTX *, unsigned char *, unsigned int)); +void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); +#endif +#endif diff -Nru sipsak-0.9.6+git20170713/src/request.c sipsak-0.9.7/src/request.c --- sipsak-0.9.6+git20170713/src/request.c 1970-01-01 00:00:00.000000000 +0000 +++ sipsak-0.9.7/src/request.c 2019-04-27 04:54:34.000000000 +0000 @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2002-2004 Fhg Fokus + * Copyright (C) 2004-2005 Nils Ohlmeier + * + * This file belongs to sipsak, a free sip testing tool. + * + * sipsak is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * sipsak is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sipsak.h" + +#ifdef HAVE_STRING_H +# include +#endif + +#include "request.h" +#include "exit_code.h" +#include "helper.h" +#include "header_f.h" + +/* create a valid sip header for the different modes */ +void create_msg(int action, char *req_buff, char *repl_buff, char *username, int cseq){ + unsigned int c, d, len; + char *req_buf_begin = req_buff; + + if(cseq == 0) { + fprintf(stderr, "error: CSeq 0 is not allowed\n"); + exit_code(253, __PRETTY_FUNCTION__, "invalid CSeq 0"); + } + if (req_buff == NULL) + abort(); + if (username == NULL) + username = ""; + c=(unsigned int)rand(); + c+=lport; + d=(unsigned int)rand(); + switch (action){ + case REQ_REG: + sprintf(req_buff, + "%s sip:%s%s" + "%ssip:%s%s;tag=%x\r\n" + "%ssip:%s%s\r\n" + "%s%u@%s\r\n" + "%s%i %s\r\n" + "%s0\r\n" + "%s70\r\n" + "%s%s\r\n", + REG_STR, domainname, SIP20_STR, + FROM_STR, username, domainname, c, + TO_STR, username, domainname, + CALL_STR, c, fqdn, + CSEQ_STR, cseq, REG_STR, + CON_LEN_STR, + MAX_FRW_STR, + UA_STR, UA_VAL_STR); + req_buff += strlen(req_buff); + if (contact_uri!=NULL) { + sprintf(req_buff, "%s%i\r\n" + "%s%s\r\n\r\n", + EXP_STR, expires_t, + CONT_STR, contact_uri); + } + else if (empty_contact == 0) { + sprintf(req_buff, "%s%i\r\n" + "%ssip:%s%s:%i", + EXP_STR, expires_t, + CONT_STR, username, fqdn, lport); + req_buff += strlen(req_buff); + if (transport != SIP_UDP_TRANSPORT) + sprintf(req_buff, "%s%s\r\n\r\n", TRANSPORT_PARAMETER_STR, + transport_str); + else + sprintf(req_buff, "\r\n\r\n"); + } + else{ + sprintf(req_buff, "\r\n"); + } + add_via(req_buf_begin); + break; + case REQ_REM: + sprintf(req_buff, + "%s sip:%s%s" + "%ssip:%s%s;tag=%x\r\n" + "%ssip:%s%s\r\n" + "%s%u@%s\r\n" + "%s%i %s\r\n" + "%s%i\r\n" + "%s0\r\n" + "%s70\r\n" + "%s%s\r\n" + "%ssip:%s%s:%i;%s0", + REG_STR, domainname, SIP20_STR, + FROM_STR, username, domainname, c, + TO_STR, username, domainname, + CALL_STR, c, fqdn, + CSEQ_STR, cseq, REG_STR, + EXP_STR, expires_t, + CON_LEN_STR, + MAX_FRW_STR, + UA_STR, UA_VAL_STR, + CONT_STR, username, fqdn, lport, CON_EXP_STR); + req_buff += strlen(req_buff); + if (transport != SIP_UDP_TRANSPORT) { + sprintf(req_buff, "\r\n\r\n"); + } + else { + sprintf(req_buff, "%s%s\r\n\r\n", TRANSPORT_PARAMETER_STR, + transport_str); + } + add_via(req_buf_begin); + break; + case REQ_INV: + sprintf(req_buff, + "%s sip:%s%s%s" + "%ssip:%s%s\r\n" + "%s%u@%s\r\n" + "%s%i %s\r\n" + "%s0\r\n" + "%ssip:sipsak@%s:%i\r\n" + "%sDONT ANSWER this test call!\r\n" + "%s70\r\n" + "%s%s\r\n", + INV_STR, username, domainname, SIP20_STR, + TO_STR, username, domainname, + CALL_STR, c, fqdn, + CSEQ_STR, cseq, INV_STR, + CON_LEN_STR, + CONT_STR, fqdn, lport, + SUB_STR, + MAX_FRW_STR, + UA_STR, UA_VAL_STR); + req_buff += strlen(req_buff); + if (from_uri) { + sprintf(req_buff, + "%s%s;tag=%x\r\n" + "\r\n", + FROM_STR, from_uri, c); + } + else { + sprintf(req_buff, + "%ssip:sipsak@%s:%i;tag=%x\r\n" + "\r\n", + FROM_STR, fqdn, lport, c); + } + add_via(req_buf_begin); + sprintf(repl_buff, + "%s" + "%ssip:sipsak@%s:%i;tag=%x\r\n" + "%ssip:%s%s;tag=%o%o\r\n" + "%s%u@%s\r\n" + "%s%i %s\r\n" + "%s0\r\n" + "%ssip:sipsak_conf@%s:%i\r\n" + "%s%s\r\n" + "\r\n", + SIP200_STR, + FROM_STR, fqdn, lport, c, + TO_STR, username, domainname, c, d, + CALL_STR, c, fqdn, + CSEQ_STR, cseq, INV_STR, + CON_LEN_STR, + CONT_STR, fqdn, lport, + UA_STR, UA_VAL_STR); + break; + case REQ_MES: + sprintf(req_buff, + "%s sip:%s%s%s" + "%ssip:%s%s\r\n" + "%s%u@%s\r\n" + "%s%i %s\r\n" + "%s%s\r\n" + "%s70\r\n" + "%s%s\r\n", + MES_STR, username, domainname, SIP20_STR, + TO_STR, username, domainname, + CALL_STR, c, fqdn, + CSEQ_STR, cseq, MES_STR, + CON_TYP_STR, TXT_PLA_STR, + MAX_FRW_STR, + UA_STR, UA_VAL_STR); + req_buff += strlen(req_buff); + if (from_uri) { + sprintf(req_buff, + "%s%s;tag=%x\r\n", + FROM_STR, from_uri, c); + } + else { + sprintf(req_buff, + "%ssip:sipsak@%s:%i;tag=%x\r\n", + FROM_STR, fqdn, lport, c); + } + req_buff += strlen(req_buff); + if (mes_body) { + len = strlen(mes_body); + } + else { + len = SIPSAK_MES_STR_LEN + strlen(username); + } + sprintf(req_buff, "%s%u\r\n", CON_LEN_STR, len); + req_buff += strlen(req_buff); + if (con_dis) { + sprintf(req_buff, "%s%s\r\n", CON_DIS_STR, con_dis); + req_buff += strlen(req_buff); + } + sprintf(req_buff, "\r\n"); + req_buff += 2; + if (mes_body) { + sprintf(req_buff, + "%s", + mes_body); + } + else { + sprintf(req_buff, "%s%s", SIPSAK_MES_STR, username); + req_buff += strlen(req_buff) - 1; + *(req_buff) = '.'; + } + add_via(req_buf_begin); + sprintf(repl_buff, + "%s" + "%ssip:sipsak@%s:%i;tag=%x\r\n" + "%ssip:%s%s;tag=%o%o\r\n" + "%s%u@%s\r\n" + "%s%i %s\r\n" + "%s0\r\n" + "%s%s\r\n" + "\r\n", + SIP200_STR, + FROM_STR, fqdn, lport, c, + TO_STR, username, domainname, c, d, + CALL_STR, c, fqdn, + CSEQ_STR, cseq, MES_STR, + CON_LEN_STR, + UA_STR, UA_VAL_STR); + break; + case REQ_OPT: + sprintf(req_buff, + "%s sip:%s%s%s" + "%ssip:sipsak@%s:%i;tag=%x\r\n" + "%ssip:%s%s\r\n" + "%s%u@%s\r\n" + "%s%i %s\r\n" + "%ssip:sipsak@%s:%i\r\n" + "%s0\r\n" + "%s70\r\n" + "%s%s\r\n" + "%s%s\r\n" + "\r\n", + OPT_STR, username, domainname, SIP20_STR, + FROM_STR, fqdn, lport, c, + TO_STR, username, domainname, + CALL_STR, c, fqdn, + CSEQ_STR, cseq, OPT_STR, + CONT_STR, fqdn, lport, + CON_LEN_STR, + MAX_FRW_STR, + UA_STR, UA_VAL_STR, + ACP_STR, TXT_PLA_STR); + add_via(req_buf_begin); + break; + case REQ_FLOOD: + sprintf(req_buff, + "%s sip:%s%s%s" + "%s%s %s:9;branch=z9hG4bK.%08x\r\n" + "%ssip:sipsak@%s:9;tag=%x\r\n" + "%ssip:%s%s\r\n" + "%s%u@%s\r\n" + "%s%i %s\r\n" + "%ssip:sipsak@%s:9\r\n" + "%s0\r\n" + "%s70\r\n" + "%s%s\r\n" + "\r\n", + FLOOD_METH, username, domainname, SIP20_STR, + VIA_SIP_STR, TRANSPORT_UDP_STR, fqdn, d, + FROM_STR, fqdn, c, + TO_STR, username, domainname, + CALL_STR, c, fqdn, + CSEQ_STR, cseq, FLOOD_METH, + CONT_STR, fqdn, + CON_LEN_STR, + MAX_FRW_STR, + UA_STR, UA_VAL_STR); + break; + case REQ_RAND: + sprintf(req_buff, + "%s sip:%s%s" + "%ssip:sipsak@%s:%i;tag=%x\r\n" + "%ssip:%s\r\n" + "%s%u@%s\r\n" + "%s%i %s\r\n" + "%ssipsak@%s:%i\r\n" + "%s0\r\n" + "%s70\r\n" + "%s%s\r\n" + "\r\n", + OPT_STR, domainname, SIP20_STR, + FROM_STR, fqdn, lport, c, + TO_STR, domainname, + CALL_STR, c, fqdn, + CSEQ_STR, cseq, OPT_STR, + CONT_STR, fqdn, lport, + CON_LEN_STR, + MAX_FRW_STR, + UA_STR, UA_VAL_STR); + add_via(req_buf_begin); + break; + default: + fprintf(stderr, "error: unknown request type to create\n"); + exit_code(2, __PRETTY_FUNCTION__, "unknown request type requested"); + break; + } + if (headers) { + insert_header(req_buf_begin, headers, 1); + if (repl_buff) + insert_header(repl_buff, headers, 1); + } +} + diff -Nru sipsak-0.9.6+git20170713/src/request.h sipsak-0.9.7/src/request.h --- sipsak-0.9.6+git20170713/src/request.h 1970-01-01 00:00:00.000000000 +0000 +++ sipsak-0.9.7/src/request.h 2019-04-27 04:54:34.000000000 +0000 @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2002-2004 Fhg Fokus + * Copyright (C) 2004-2005 Nils Ohlmeier + * + * This file belongs to sipsak, a free sip testing tool. + * + * sipsak is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * sipsak is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef SIPSAK_REQUEST_H +#define SIPSAK_REQUEST_H + +void create_msg(int action, char *buff, char *repl_buff, char *username, int cseq); + +#endif diff -Nru sipsak-0.9.6+git20170713/src/shoot.c sipsak-0.9.7/src/shoot.c --- sipsak-0.9.6+git20170713/src/shoot.c 1970-01-01 00:00:00.000000000 +0000 +++ sipsak-0.9.7/src/shoot.c 2019-04-27 04:54:34.000000000 +0000 @@ -0,0 +1,1111 @@ +/* + * Copyright (C) 2002-2004 Fhg Fokus + * Copyright (C) 2004-2005 Nils Ohlmeier + * + * This file belongs to sipsak, a free sip testing tool. + * + * sipsak is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * sipsak is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sipsak.h" + +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else +# ifdef HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif /* TIME_WITH_SYS_TIME */ +#ifdef HAVE_UNISTD_H +# ifdef HAVE_SYS_TYPES_H +# include +# endif +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#include "shoot.h" + +#include "request.h" +#include "auth.h" +#include "header_f.h" +#include "helper.h" +#include "exit_code.h" +#include "transport.h" + +#ifndef DEFAULT_RETRYS +#define DEFAULT_RETRYS 5 +#endif + +#ifndef DEFAULT_TIMEOUT +#define DEFAULT_TIMEOUT 5000 +#endif + +char *usern; + +enum usteps usrlocstep; + +struct sipsak_regexp regexps; + +struct sipsak_sr_time timers; +struct sipsak_con_data cdata; +struct sipsak_counter counters; +struct sipsak_delay delays; + +/* if a reply was received successfully, return success, unless + * reply matching is enabled and no match occurred + */ + +static inline void on_success(char *_response) +{ + if ((_response != NULL) && regex && + regexec(regex, _response, 0, 0, 0) == REG_NOMATCH) { + log_message(request); + fprintf(stderr, "error: RegExp failed\n"); + exit_code(32, __PRETTY_FUNCTION__, "regular expression failed"); + } else { + exit_code(0, __PRETTY_FUNCTION__, NULL); + } +} + +/* just print the given username and number into the first buffer and + * append an @ char */ +static inline void create_usern(char *target, char *username, int number) +{ + if (number >= 0) { + sprintf(target, "%s%i@", username, number); + } + else { + sprintf(target, "%s@", username); + } +} + +/* tries to take care of a redirection */ +void handle_3xx(struct sockaddr_in *tadr) +{ + char *uscheme, *uuser, *uhost, *contact; + + printf("** received redirect "); + if (warning_ext == 1) { + printf("from "); + warning_extract(received); + printf("\n"); + } + else + printf("\n"); + /* we'll try to handle 301 and 302 here, other 3xx are to complex */ + regcomp(&(regexps.redexp), "^SIP/[0-9]\\.[0-9] 30[125] ", + REG_EXTENDED|REG_NOSUB|REG_ICASE); + if (regexec(&(regexps.redexp), received, 0, 0, 0) == REG_NOERROR) { + /* try to find the contact in the redirect */ + contact = uri_from_contact(received); + if (contact==NULL) { + fprintf(stderr, "error: cannot find Contact in this " + "redirect:\n%s\n", received); + exit_code(3, __PRETTY_FUNCTION__, "missing Contact header in reply"); + } + /* correct our request */ + uri_replace(request, contact); + new_transaction(request, response); + /* extract the needed information*/ + rport = 0; + address = 0; + parse_uri(contact, &uscheme, &uuser, &uhost, &rport); + if (!rport) + address = getsrvadr(uhost, &rport, &transport); + if (!address) + address = getaddress(uhost); + if (!address){ + fprintf(stderr, "error: cannot determine host " + "address from Contact of redirect:" + "\n%s\n", received); + exit_code(2, __PRETTY_FUNCTION__, "missing host in Contact header"); + } + if (!rport) { + rport = 5060; + } + free(contact); + if (!outbound_proxy) + cdata.connected = set_target(tadr, address, rport, cdata.csock, cdata.connected); + } + else { + fprintf(stderr, "error: cannot handle this redirect:" + "\n%s\n", received); + exit_code(2, __PRETTY_FUNCTION__, "unsupported redirect reply"); + } +} + +/* takes care of replies in the trace route mode */ +void trace_reply() +{ + char *contact; + + if (regexec(&(regexps.tmhexp), received, 0, 0, 0) == REG_NOERROR) { + /* we received 483 to many hops */ + printf("%i: ", namebeg); + if (verbose > 2) { + printf("(%.3f ms)\n%s\n", + deltaT(&(timers.sendtime), &(timers.recvtime)), received); + } + else { + warning_extract(received); + printf("(%.3f ms) ", deltaT(&(timers.sendtime), &(timers.recvtime))); + print_message_line(received); + } + namebeg++; + cseq_counter++; + create_msg(REQ_OPT, request, NULL, usern, cseq_counter); + set_maxforw(request, namebeg); + return; + } + else if (regexec(&(regexps.proexp), received, 0, 0, 0) == REG_NOERROR) { + /* we received a provisional response */ + printf("%i: ", namebeg); + if (verbose > 2) { + printf("(%.3f ms)\n%s\n", + deltaT(&(timers.sendtime), &(timers.recvtime)), received); + } + else { + warning_extract(received); + printf("(%.3f ms) ", deltaT(&(timers.sendtime), &(timers.recvtime))); + print_message_line(received); + } + delays.retryAfter = timer_t2; + cdata.dontsend=1; + return; + } + else { + /* anything else then 483 or provisional will + be treated as final */ + printf("%i: ", namebeg); + warning_extract(received); + printf("(%.3f ms) ", deltaT(&(timers.sendtime), &(timers.recvtime))); + print_message_line(received); + if ((contact = STRCASESTR(received, CONT_STR)) != NULL || + (contact = STRCASESTR(received, CONT_SHORT_STR)) != NULL) { + if (*contact == '\n') { + contact++; + } + printf("\t"); + print_message_line(contact); + } + else { + printf("\twithout Contact header\n"); + } + if (regexec(&(regexps.okexp), received, 0, 0, 0) == REG_NOERROR) { + on_success(received); + } else { + log_message(request); + exit_code(1, __PRETTY_FUNCTION__, "received final non-2xx reply"); + } + } +} + +/* takes care of replies in the default mode */ +void handle_default() +{ + /* in the normal send and reply case anything other + then 1xx will be treated as final response*/ + if (regexec(&(regexps.proexp), received, 0, 0, 0) == REG_NOERROR) { + if (verbose > 1) { + printf("%s\n\n", received); + printf("** reply received "); + if ((counters.send_counter == 1) || (STRNCASECMP(request, ACK_STR, ACK_STR_LEN) == 0)) { + printf("after %.3f ms **\n", deltaT(&(timers.firstsendt), &(timers.recvtime))); + } + else { + printf("%.3f ms after first send\n and " + "%.3f ms after last send **\n", deltaT(&(timers.firstsendt), &(timers.recvtime)), + deltaT(&(timers.sendtime), &(timers.recvtime))); + } + printf(" "); + print_message_line(received); + printf(" provisional received; still" + " waiting for a final response\n"); + } + if (inv_trans) { + delays.retryAfter = timer_final; + } + else { + delays.retryAfter = timer_t2; + } + cdata.dontsend = 1; + return; + } + else { + if (verbose > 1) { + printf("%s\n\n", received); + printf("** reply received "); + if ((counters.send_counter == 1) || (STRNCASECMP(request, ACK_STR, ACK_STR_LEN) == 0)){ + printf("after %.3f ms **\n", deltaT(&(timers.firstsendt), &(timers.recvtime))); + } + else { + printf("%.3f ms after first send\n and " + "%.3f ms after last send **\n", deltaT(&(timers.firstsendt), &(timers.recvtime)), + deltaT(&(timers.sendtime), &(timers.recvtime))); + } + printf(" "); + print_message_line(received); + printf(" final received\n"); + } + else if (verbose>0) { + printf("%s\n", received); + } + if (timing > 0) { + timing--; + if (timing == 0) { + if (counters.run == 0) { + counters.run++; + } + printf("%.3f/%.3f/%.3f ms\n", delays.small_delay, delays.all_delay / counters.run, delays.big_delay); + } + else { + counters.run++; + new_transaction(request, response); + delays.retryAfter = timer_t1; + } + } + if (timing == 0) { + if (regexec(&(regexps.okexp), received, 0, 0, 0) == REG_NOERROR) { + on_success(received); + } + else { + log_message(request); + exit_code(1, __PRETTY_FUNCTION__, "received final non-2xx reply"); + } + } + } +} + +/* takes care of replies in the readntrash mode */ +void handle_randtrash() +{ + /* in randomzing trash we are expexting 4?? error codes + everything else should not be normal */ + if (regexec(&(regexps.errexp), received, 0, 0, 0) == REG_NOERROR) { + if (verbose > 2) + printf("received:\n%s\n", received); + if (verbose > 1) { + printf("received expected 4xx "); + if (warning_ext == 1) { + printf ("from "); + warning_extract(received); + printf("\n"); + } + else { + printf("\n"); + } + } + } + else { + fprintf(stderr, "warning: did not received 4xx\n"); + if (verbose > 1) + printf("sended:\n%s\nreceived:\n%s\n", request, received); + } + if (cseq_counter == nameend) { + if (counters.randretrys == 0) { + printf("random end reached. server survived :) respect!\n"); + exit_code(0, __PRETTY_FUNCTION__, NULL); + } + else { + printf("maximum sendings reached but did not " + "get a response on this request:\n%s\n", request); + log_message(request); + exit_code(3, __PRETTY_FUNCTION__, "missing reply on trashed request"); + } + } + else { + trash_random(request); + } +} + +/* takes care of replies in the usrloc mode */ +void handle_usrloc() +{ + char *crlf; + char ruri[11+12+20]; //FIXME: username length 20 should be dynamic + + if (regexec(&(regexps.proexp), received, 0, 0, 0) == REG_NOERROR) { + if (verbose > 2) { + print_message_line(received); + printf("ignoring provisional response\n\n"); + } + if (inv_trans) { + delays.retryAfter = timer_final; + } + else { + delays.retryAfter = timer_t2; + } + cdata.dontsend = 1; + } + else { + switch (usrlocstep) { + case REG_REP: + /* we have sent a register and look + at the response now */ + if (regexec(&(regexps.okexp), received, 0, 0, 0) == REG_NOERROR) { + if (verbose > 1) { + printf ("\tOK\n"); + } + if (verbose > 2) { + printf("\n%s\n", received); + } + } + else { + fprintf(stderr, "received:\n%s\nerror: didn't " + "received '200 OK' on register (see " + "above). aborting\n", received); + log_message(request); + exit_code(1, __PRETTY_FUNCTION__, "received non-2xx reply for REGISTER"); + } + if (invite == 0 && message == 0) { + if (namebeg==nameend) { + if (verbose>0) { + printf("\nAll usrloc tests" + " completed successful.\nreceived" + " last message %.3f ms after first" + " request (test duration).\n", + deltaT(&(timers.firstsendt), &(timers.recvtime))); + } + if (delays.big_delay>0 && verbose>0) { + printf("biggest delay between " + "request and response was %.3f" + " ms\n", delays.big_delay); + } + if (counters.retrans_r_c>0 && verbose>0) { + printf("%i retransmission(s) received from server.\n", + counters.retrans_r_c); + } + if (counters.retrans_s_c>0 && verbose>0) { + printf("%i time(s) the timeout of " + "%i ms exceeded and request was" + " retransmitted.\n", + counters.retrans_s_c, delays.retryAfter); + if (counters.retrans_s_c > nagios_warn) { + log_message(request); + exit_code(4, __PRETTY_FUNCTION__, "#retransmissions above nagios warn level"); + } + } + if (timing) { + printf("%.3f ms\n", + deltaT(&(timers.firstsendt), &(timers.recvtime))); + } + on_success(received); + } /* namebeg == nameend */ + /* lets see if we deceid to remove a + binding (case 6)*/ + if ( ((float)rand()/RAND_MAX)*100 > rand_rem) { + namebeg++; + cseq_counter++; + create_usern(usern, username, namebeg); + create_msg(REQ_REG, request, NULL, usern, cseq_counter); + } + else { + /* to prevent only removing of low + user numbers new random number*/ + cseq_counter++; + create_usern(usern, username, ((float)rand()/RAND_MAX) * namebeg); + create_msg(REQ_REM, request, NULL, usern, cseq_counter); + usrlocstep=UNREG_REP; + } + } /* invite == 0 && message == 0 */ + else if (invite == 1) { + cseq_counter++; + create_msg(REQ_INV, request, response, usern, cseq_counter); + inv_trans = 1; + usrlocstep=INV_RECV; + } + else if (message == 1) { + cseq_counter++; + create_msg(REQ_MES, request, response, usern, cseq_counter); + inv_trans = 0; + usrlocstep=MES_RECV; + } + break; + case INV_RECV: + /* see if we received our invite */ + sprintf(ruri, "%s sip:%s", INV_STR, usern); + if (!STRNCASECMP(received, ruri, strlen(ruri))) { + if (verbose > 1) { + printf("\t\treceived invite\n"); + } + if (verbose > 2) { + printf("\n%s\n", received); + } + cpy_vias(received, response); + cpy_rr(received, response, 0); + swap_ptr(&request, &response); + usrlocstep=INV_OK_RECV; + inv_trans = 0; + } + else { + fprintf(stderr, "received:\n%s\nerror: did not " + "received the INVITE that was sent " + "(see above). aborting\n", received); + log_message(request); + exit_code(1, __PRETTY_FUNCTION__, "did not received our own INVITE request"); + } + break; + case INV_OK_RECV: + /* did we received our ok ? */ + if (STRNCASECMP(received, INV_STR, INV_STR_LEN)==0) { + if (verbose>0) { + printf("ignoring INVITE retransmission\n"); + } + counters.retrans_r_c++; + cdata.dontsend=1; + return; + } + if (regexec(&(regexps.okexp), received, 0, 0, 0) == REG_NOERROR) { + if (verbose > 1) { + printf("\t200 OK received\n"); + } + if (verbose > 2) { + printf("\n%s\n", received); + } + /* ACK was send already earlier generically */ + usrlocstep=INV_ACK_RECV; + cdata.dontsend=1; + } + else { + fprintf(stderr, "received:\n%s\nerror: did not " + "received the '200 OK' that was sent " + "as the reply on the INVITE (see " + "above). aborting\n", received); + log_message(request); + exit_code(1, __PRETTY_FUNCTION__, "did not received our own 200 reply"); + } + break; + case INV_ACK_RECV: + /* did we received our ack */ + if (STRNCASECMP(received, SIP200_STR, SIP200_STR_LEN)==0) { + if (verbose>0) { + printf("ignoring 200 OK retransmission\n"); + } + counters.retrans_r_c++; + cdata.dontsend=1; + return; + } + sprintf(ruri, "%s sip:sipsak_conf@", ACK_STR); + if (STRNCASECMP(received, ruri, strlen(ruri))==0) { + if (verbose > 1) { + printf("\tACK received\n"); + } + if (verbose > 2) { + printf("\n%s\n", received); + } + if (verbose>0 && nameend>0) { + printf("usrloc for %s%i completed " + "successful\n", username, namebeg); + } + else if (verbose>0) { + printf("usrloc for %s completed successful\n", username); + } + if (namebeg==nameend) { + if (verbose>0) { + printf("\nAll usrloc tests completed " + "successful.\nreceived last message" + " %.3f ms after first request (test" + " duration).\n", deltaT(&(timers.firstsendt), &(timers.recvtime))); + } + if (delays.big_delay>0) { + printf("biggest delay between " + "request and response was %.3f" + " ms\n", delays.big_delay); + } + if (counters.retrans_r_c>0) { + printf("%i retransmission(s) received from server.\n", + counters.retrans_r_c); + } + if (counters.retrans_s_c>0) { + printf("%i time(s) the timeout of " + "%i ms exceeded and request was" + " retransmitted.\n", + counters.retrans_s_c, delays.retryAfter); + if (counters.retrans_s_c > nagios_warn) { + log_message(request); + exit_code(4, __PRETTY_FUNCTION__, "#retransmissions above nagios warn level"); + } + } + on_success(received); + } /* namebeg == nameend */ + if (usrloc == 1) { + /* lets see if we deceid to remove a + binding (case 6)*/ + if (((float)rand()/RAND_MAX) * 100 > rand_rem) { + namebeg++; + cseq_counter++; + create_usern(usern, username, namebeg); + create_msg(REQ_REG, request, NULL, usern, cseq_counter); + usrlocstep=REG_REP; + } + else { + /* to prevent only removing of low + user numbers new random number*/ + cseq_counter++; + create_usern(usern, username, ((float)rand()/RAND_MAX) * namebeg); + create_msg(REQ_REM, request, NULL, usern, cseq_counter); + usrlocstep=UNREG_REP; + } + } /* usrloc == 1 */ + else { + namebeg++; + cseq_counter++; + create_usern(usern, username, namebeg); + create_msg(REQ_INV, request, response, usern, cseq_counter); + inv_trans = 1; + usrlocstep=INV_RECV; + } + } /* STRNCASECMP */ + else { + fprintf(stderr, "received:\n%s\nerror: did not " + "received the 'ACK' that was sent " + "as the reply on the '200 OK' (see " + "above). aborting\n", received); + log_message(request); + exit_code(1, __PRETTY_FUNCTION__, "missing ACK that was send by myself"); + } + break; + case MES_RECV: + /* we sent the message and look if its + forwarded to us */ + sprintf(ruri, "%s sip:%s", MES_STR, usern); + if (!STRNCASECMP(received, ruri, strlen(ruri))) { + if (verbose > 1) { + crlf=STRCASESTR(received, "\r\n\r\n"); + crlf=crlf+4; + printf(" received message\n '%s'\n", crlf); + } + if (verbose > 2) { + printf("\n%s\n", received); + } + cpy_vias(received, response); + swap_ptr(&request, &response); + usrlocstep=MES_OK_RECV; + } + else { + fprintf(stderr, "received:\n%s\nerror: did not " + "received the 'MESSAGE' that was sent " + "(see above). aborting\n", received); + log_message(request); + exit_code(1, __PRETTY_FUNCTION__, "did not received my own MESSAGE request"); + } + break; + case MES_OK_RECV: + /* we sent our reply on the message and + look if this is also forwarded to us */ + if (STRNCASECMP(received, MES_STR, MES_STR_LEN)==0) { + if (verbose>0) { + printf("ignoring MESSAGE retransmission\n"); + } + counters.retrans_r_c++; + cdata.dontsend=1; + return; + } + if (regexec(&(regexps.okexp), received, 0, 0, 0) == REG_NOERROR) { + if (verbose > 1) { + printf(" reply received\n\n"); + } + else if (verbose>0 && nameend>0) { + printf("usrloc for %s%i completed " + "successful\n", username, namebeg); + } + else if (verbose>0) { + printf("usrloc for %s completed successful\n", username); + } + if (namebeg==nameend) { + if (verbose>0) { + printf("\nAll usrloc tests completed " + "successful.\nreceived last message" + " %.3f ms after first request (test" + " duration).\n", deltaT(&(timers.firstsendt), &(timers.recvtime))); + } + if (delays.big_delay>0) { + printf("biggest delay between " + "request and response was %.3f" + " ms\n", delays.big_delay); + } + if (counters.retrans_r_c>0) { + printf("%i retransmission(s) " + "received from server.\n", + counters.retrans_r_c); + } + if (counters.retrans_s_c>0) { + printf("%i time(s) the timeout of " + "%i ms exceeded and request was" + " retransmitted.\n", + counters.retrans_s_c, delays.retryAfter); + if (counters.retrans_s_c > nagios_warn) { + log_message(request); + exit_code(4, __PRETTY_FUNCTION__, "#retransmissions above nagios warn level"); + } + } + on_success(received); + } /* namebeg == nameend */ + if (usrloc == 1) { + /* lets see if we deceid to remove a + binding (case 6)*/ + if (((float)rand()/RAND_MAX) * 100 > rand_rem) { + namebeg++; + cseq_counter++; + create_usern(usern, username, namebeg); + create_msg(REQ_REG, request, NULL, usern, cseq_counter); + usrlocstep=REG_REP; + } + else { + /* to prevent only removing of low + user numbers new random number*/ + cseq_counter++; + create_usern(usern, username, ((float)rand()/RAND_MAX) * namebeg); + create_msg(REQ_REM, request, NULL, usern, cseq_counter); + usrlocstep=UNREG_REP; + } + } /* usrloc == 1 */ + else { + namebeg++; + cseq_counter++; + create_usern(usern, username, namebeg); + create_msg(REQ_MES, request, NULL, usern, cseq_counter); + usrlocstep=MES_RECV; + } + } /* regexec */ + else { + if (verbose>0) { + if (mes_body) { + fprintf(stderr, "received:\n%s\nerror: did" + " not received 200 for the " + "MESSAGE (see above)\n", + received); + } + else { + fprintf(stderr, "received:\n%s\nerror: did" + " not received the '200 OK' " + "that was sent as the reply on" + " the MESSAGE (see above). " + "aborting\n", received); + } + } + log_message(request); + exit_code(1, __PRETTY_FUNCTION__, "received non-2xx reply for MESSAGE request"); + } + break; + case UNREG_REP: + if (STRNCASECMP(received, MES_STR, MES_STR_LEN)==0) { + if (verbose>0) { + printf("ignoring MESSAGE retransmission\n"); + } + counters.retrans_r_c++; + cdata.dontsend=1; + return; + } + if (regexec(&(regexps.okexp), received, 0, 0, 0) == REG_NOERROR) { + if (verbose > 1) { + printf(" OK\n\n"); + } + else if (verbose>0 && nameend>0) { + printf("Binding removal for %s%i " + "successful\n", username, namebeg); + } + else if (verbose>0) { + printf("Binding removal for %s successful\n", username); + } + namebeg++; + cseq_counter++; + create_usern(usern, username, namebeg); + create_msg(REQ_REG, request, NULL, usern, cseq_counter); + usrlocstep=REG_REP; + } + else { + fprintf(stderr, "received:\n%s\nerror: did not " + "received the expected 200 on the " + "remove bindings request for %s%i (see" + " above). aborting\n", received, username, + namebeg); + log_message(request); + exit_code(1, __PRETTY_FUNCTION__, "received non-2xx reply for de-register request"); + } + break; + default: + fprintf(stderr, "error: unknown step in usrloc\n"); + exit_code(2, __PRETTY_FUNCTION__, "unknown step in usrloc"); + break; + } /* switch */ + } /* regexec proexp */ +} + +void before_sending() +{ + /* some initial output */ + if ((usrloc == 1||invite == 1||message == 1) && (verbose > 1) && (cdata.dontsend == 0)) { + switch (usrlocstep) { + case REG_REP: + if (nameend>0) + printf("registering user %s%i... ", username, namebeg); + else + printf("registering user %s... ", username); + break; + case INV_RECV: + if (nameend>0) + printf("inviting user %s%i... ", username, namebeg); + else + printf("inviting user %s... ", username); + break; + case INV_OK_RECV: + printf("sending invite reply... "); + break; + case INV_ACK_RECV: + printf("sending invite ack... "); + break; + case MES_RECV: + if (nameend>0) + printf("sending message to %s%i... ", username, namebeg); + else + printf("sending message to %s... ", username); + break; + case MES_OK_RECV: + if (mes_body) + printf("sending message ... \n"); + else + printf("sending message reply... "); + break; + case UNREG_REP: + if (nameend>0) + printf("remove binding for %s%i...", username, namebeg); + else + printf("remove binding for %s...", username); + break; + } + } /* if usrloc...*/ + else if (flood == 1 && verbose > 0) { + printf("flooding message number %i\n", namebeg); + } + else if (randtrash == 1 && verbose > 0) { + printf("message with %i randomized chars\n", cseq_counter); + if (verbose > 2) + printf("request:\n%s\n", request); + } +} + +/* this is the main function with the loops and modes */ +void shoot(char *buf, int buff_size) +{ + struct timespec sleep_ms_s, sleep_rem; + int ret, cseqtmp, rand_tmp; + char buf2[BUFSIZE], buf3[BUFSIZE], lport_str[LPORT_STR_LEN]; + + /* delays.retryAfter = DEFAULT_TIMEOUT; */ + if (transport == SIP_UDP_TRANSPORT) { + delays.retryAfter = timer_t1; + } + else { + delays.retryAfter = timer_final; + } + inv_trans = 0; + cseq_counter = 1; + usrlocstep = REG_REP; + + /* initalize local vars */ + cdata.dontsend=cdata.dontrecv=counters.retrans_r_c=counters.retrans_s_c= 0; + delays.big_delay=counters.send_counter=counters.run= 0; + timers.delaytime.tv_sec = 0; + timers.delaytime.tv_usec = 0; + usern = NULL; + /* initialize local arrays */ + memset(buf2, 0, BUFSIZE); + memset(buf3, 0, BUFSIZE); + memset(lport_str, 0, LPORT_STR_LEN); + + cdata.csock = cdata.usock = -1; + cdata.connected = 0; + cdata.buf_tmp = NULL; + cdata.buf_tmp_size = 0; + + memset(&(timers.sendtime), 0, sizeof(timers.sendtime)); + memset(&(timers.recvtime), 0, sizeof(timers.recvtime)); + memset(&(timers.firstsendt), 0, sizeof(timers.firstsendt)); + memset(&(timers.starttime), 0, sizeof(timers.starttime)); + memset(&(timers.delaytime), 0, sizeof(timers.delaytime)); + + request = buf; + response = buf2; + received = buf3; + + create_sockets(&cdata); + + if (sleep_ms != 0) { + if (sleep_ms == -2) { + rand_tmp = rand(); + sleep_ms_s.tv_sec = rand_tmp / 1000; + sleep_ms_s.tv_nsec = (rand_tmp % 1000) * 1000000; + } + else { + sleep_ms_s.tv_sec = sleep_ms / 1000; + sleep_ms_s.tv_nsec = (sleep_ms % 1000) * 1000000; + } + } + + if (replace_b == 1){ + replace_string(request, "$dsthost$", domainname); + replace_string(request, "$srchost$", fqdn); + sprintf(lport_str, "%i", lport); + replace_string(request, "$port$", lport_str); + if (username) + replace_string(request, "$user$", username); + } + if (replace_str) + replace_strings(request, replace_str); + + /* set all regular expression to simplfy the result code identification */ + regcomp(&(regexps.replyexp), "^SIP/[0-9]\\.[0-9] [1-6][0-9][0-9]", + REG_EXTENDED|REG_NOSUB|REG_ICASE); + regcomp(&(regexps.proexp), "^SIP/[0-9]\\.[0-9] 1[0-9][0-9] ", + REG_EXTENDED|REG_NOSUB|REG_ICASE); + regcomp(&(regexps.okexp), "^SIP/[0-9]\\.[0-9] 2[0-9][0-9] ", + REG_EXTENDED|REG_NOSUB|REG_ICASE); + regcomp(&(regexps.redexp), "^SIP/[0-9]\\.[0-9] 3[0-9][0-9] ", + REG_EXTENDED|REG_NOSUB|REG_ICASE); + regcomp(&(regexps.authexp), "^SIP/[0-9]\\.[0-9] 40[17] ", + REG_EXTENDED|REG_NOSUB|REG_ICASE); + regcomp(&(regexps.errexp), "^SIP/[0-9]\\.[0-9] 4[0-9][0-9] ", + REG_EXTENDED|REG_NOSUB|REG_ICASE); + regcomp(&(regexps.tmhexp), "^SIP/[0-9]\\.[0-9] 483 ", + REG_EXTENDED|REG_NOSUB|REG_ICASE); + + if (username) { + if (nameend > 0) { + usern = str_alloc(strlen(username) + 12); + create_usern(usern, username, namebeg); + } + else { + if (*(username + strlen(username) - 1) != '@') { + usern = str_alloc(strlen(username) + 2); + create_usern(usern, username, -1); + } + else { + usern = username; + } + } + } + + if (usrloc == 1||invite == 1||message == 1){ + /* calculate the number of required steps and create initial mes */ + if (usrloc == 1) { + create_msg(REQ_REG, request, NULL, usern, cseq_counter); + usrlocstep=REG_REP; + } + else if (invite == 1) { + create_msg(REQ_INV, request, response, usern, cseq_counter); + inv_trans = 1; + usrlocstep=INV_RECV; + } + else { + create_msg(REQ_MES, request, response, usern, cseq_counter); + if (mes_body) + usrlocstep=MES_OK_RECV; + else + usrlocstep=MES_RECV; + } + } + else if (trace == 1){ + /* for trace we need some spezial initis */ + namebeg=0; + create_msg(REQ_OPT, request, NULL, usern, cseq_counter); + set_maxforw(request, namebeg); + } + else if (flood == 1){ + if (nameend<=0) nameend=INT_MAX; + namebeg=1; + create_msg(REQ_FLOOD, request, NULL, usern, cseq_counter); + } + else if (randtrash == 1){ + counters.randretrys=0; + namebeg=1; + create_msg(REQ_RAND, request, NULL, usern, cseq_counter); + nameend=(int)strlen(request); + if (trashchar == 1){ + if (trashchar < nameend) + nameend=trashchar; + else + fprintf(stderr, "warning: number of trashed chars to big. setting to " + "request length\n"); + } + trash_random(request); + } + else { + /* for none of the modes we also need some inits */ + if (file_b == 0) { + namebeg=1; + create_msg(REQ_OPT, request, NULL, usern, cseq_counter); + } + else { + if (STRNCASECMP(request, INV_STR, INV_STR_LEN) == 0) { + inv_trans = 1; + } + if(via_ins == 1) + add_via(request); + } + /* delays.retryAfter = delays.retryAfter / 10; */ + if(maxforw!=-1) + set_maxforw(request, maxforw); + } + + cdata.connected = set_target(&(cdata.adr), address, rport, cdata.csock, cdata.connected); + + /* here we go until someone decides to exit */ + while(1) { + before_sending(); + + if (sleep_ms == -2) { + rand_tmp = rand(); + sleep_ms_s.tv_sec = rand_tmp / 1000; + sleep_ms_s.tv_nsec = (rand_tmp % 1000) * 1000; + } else if (sleep_ms != 0) { + sleep_ms_s.tv_sec = sleep_ms; + sleep_ms_s.tv_nsec = 0; + } + if (sleep_ms != 0) { + dbg("sleeping for %li s + %li ns\n", sleep_ms_s.tv_sec, sleep_ms_s.tv_nsec); + nanosleep(&sleep_ms_s, &sleep_rem); + } + + send_message(request, &cdata, &counters, &timers); + + /* in flood we are only interested in sending so skip the rest */ + if (flood == 0) { + ret = recv_message(received, BUFSIZE, inv_trans, &delays, &timers, + &counters, &cdata, ®exps); + if(ret > 0) + { + if (usrlocstep == INV_OK_RECV) { + swap_ptr(&response, &request); + } + /* send ACK for non-provisional reply on INVITE */ + if ((STRNCASECMP(request, "INVITE", 6)==0) && + (regexec(&(regexps.replyexp), received, 0, 0, 0) == REG_NOERROR) && + (regexec(&(regexps.proexp), received, 0, 0, 0) == REG_NOMATCH)) { + build_ack(request, received, response, ®exps); + cdata.dontsend = 0; + inv_trans = 0; + /* lets fire the ACK to the server */ + send_message(response, &cdata, &counters, &timers); + inv_trans = 1; + } + /* check for old CSeq => ignore retransmission */ + cseqtmp = cseq(received); + if ((0 < cseqtmp) && (cseqtmp < cseq_counter)) { + if (verbose>0) { + printf("ignoring retransmission\n"); + } + counters.retrans_r_c++; + cdata.dontsend = 1; + continue; + } + else if (regexec(&(regexps.authexp), received, 0, 0, 0) == REG_NOERROR) { + if (!username && !auth_username) { + if (timing > 0) { + timing--; + if (timing == 0) { + if (counters.run == 0) { + counters.run++; + } + printf("%.3f/%.3f/%.3f ms\n", delays.small_delay, delays.all_delay / counters.run, delays.big_delay); + exit_code(0, __PRETTY_FUNCTION__, NULL); + } + counters.run++; + new_transaction(request, response); + delays.retryAfter = timer_t1; + continue; + } + fprintf(stderr, "%s\nerror: received 40[17] but cannot " + "authentication without a username or auth username\n", received); + log_message(request); + exit_code(2, __PRETTY_FUNCTION__, "missing username for authentication"); + } + /* prevents a strange error */ + regcomp(&(regexps.authexp), "^SIP/[0-9]\\.[0-9] 40[17] ", REG_EXTENDED|REG_NOSUB|REG_ICASE); + insert_auth(request, received); + if (verbose > 2) + printf("\nreceived:\n%s\n", received); + new_transaction(request, response); + continue; + } /* if auth...*/ + /* lets see if received a redirect */ + if (redirects == 1 && regexec(&(regexps.redexp), received, 0, 0, 0) == REG_NOERROR) { + handle_3xx(&(cdata.adr)); + } /* if redircts... */ + else if (trace == 1) { + trace_reply(); + } /* if trace ... */ + else if (usrloc == 1||invite == 1||message == 1) { + handle_usrloc(); + } + else if (randtrash == 1) { + handle_randtrash(); + } + else { + handle_default(); + } /* redirect, auth, and modes */ + } /* ret > 0 */ + else if (ret == -1) { // we did not got anything back, send again + /* no re-transmission on reliable transports */ + if (transport != SIP_UDP_TRANSPORT) { + cdata.dontsend = 1; + } + continue; + } + else if (ret == -2) { // we received non-matching ICMP + cdata.dontsend = 1; + continue; + } + else { + if (usrloc == 1) { + printf("failed\n"); + } + perror("socket error"); + exit_code(3, __PRETTY_FUNCTION__, "internal socket error"); + } + } /* !flood */ + else { + if (counters.send_counter == 1) { + memcpy(&(timers.firstsendt), &(timers.sendtime), sizeof(struct timeval)); + } + if (namebeg==nameend) { + printf("flood end reached\n"); + printf("it took %.3f ms seconds to send %i request.\n", + deltaT(&(timers.firstsendt), &(timers.sendtime)), namebeg); + printf("we sent %f requests per second.\n", + (namebeg/(deltaT(&(timers.firstsendt), &(timers.sendtime)))*1000)); + exit_code(0, __PRETTY_FUNCTION__, NULL); + } + namebeg++; + cseq_counter++; + create_msg(REQ_FLOOD, request, NULL, usern, cseq_counter); + } + } /* while 1 */ + + /* this should never happen any more... */ + if (randtrash == 1) { + exit_code(0, __PRETTY_FUNCTION__, NULL); + } + printf("** give up retransmissioning....\n"); + if (counters.retrans_r_c>0 && (verbose > 1)) { + printf("%i retransmissions received during test\n", counters.retrans_r_c); + } + if (counters.retrans_s_c>0 && (verbose > 1)) { + printf("sent %i retransmissions during test\n", counters.retrans_s_c); + } + exit_code(3, __PRETTY_FUNCTION__, "got outside of endless messaging loop"); +} diff -Nru sipsak-0.9.6+git20170713/src/shoot.h sipsak-0.9.7/src/shoot.h --- sipsak-0.9.6+git20170713/src/shoot.h 1970-01-01 00:00:00.000000000 +0000 +++ sipsak-0.9.7/src/shoot.h 2019-04-27 04:54:34.000000000 +0000 @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2002-2004 Fhg Fokus + * Copyright (C) 2004-2005 Nils Ohlmeier + * + * This file belongs to sipsak, a free sip testing tool. + * + * sipsak is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * sipsak is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef SIPSAK_SHOOT_H +#define SIPSAK_SHOOT_H + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#define LPORT_STR_LEN 6 + +struct sipsak_regexp { + regex_t redexp; + regex_t proexp; + regex_t okexp; + regex_t tmhexp; + regex_t errexp; + regex_t authexp; + regex_t replyexp; +}; + +enum usteps { + REG_REP, + INV_RECV, + INV_OK_RECV, + INV_ACK_RECV, + MES_RECV, + MES_OK_RECV, + UNREG_REP +}; + +int inv_trans; + +void shoot(char *buff, int buff_size); + +#endif diff -Nru sipsak-0.9.6+git20170713/src/sipsak.c sipsak-0.9.7/src/sipsak.c --- sipsak-0.9.6+git20170713/src/sipsak.c 1970-01-01 00:00:00.000000000 +0000 +++ sipsak-0.9.7/src/sipsak.c 2019-04-27 04:54:34.000000000 +0000 @@ -0,0 +1,1103 @@ +/* + * Copyright (C) 2002-2004 Fhg Fokus + * Copyright (C) 2004-2005 Nils Ohlmeier + * + * This file belongs to sipsak, a free sip testing tool. + * + * sipsak is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * sipsak is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* sipsak written by nils ohlmeier (ohlmeier@fokus.fraunhofer.de). + based up on a modifyed version of shoot. + return codes are now: 0 for an received 200, 1 for all other + received responses, 2 for local errors, and 3 for remote errors. +*/ + +/* changes by jiri@iptel.org; now messages can be really received; + status code returned is 2 for some local errors , 0 for success + and 1 for remote error -- ICMP/timeout; can be used to test if + a server is alive; 1xx messages are now ignored; windows support + dropped +*/ + +#include "sipsak.h" + +#ifdef HAVE_UNISTD_H +# ifdef HAVE_SYS_TYPES_H +# include +# endif +# include +#endif +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else +# ifdef HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif +#ifdef HAVE_SYS_WAIT_H +# include +#endif +#ifdef HAVE_GETOPT_H +# include +#endif +#ifdef HAVE_SYSLOG_H +# include +#endif + +#include "helper.h" +#include "header_f.h" +#include "shoot.h" +#include "exit_code.h" + +static void sigchld_handler(int signo) +{ + int chld_status; + pid_t chld; + + while ((chld = waitpid(-1, &chld_status, WNOHANG)) > 0); +} + + +void print_version() { + printf("%s %s by Nils Ohlmeier\n", PACKAGE_NAME, PACKAGE_VERSION); + printf(" Copyright (C) 2002-2004 FhG Fokus\n"); + printf(" Copyright (C) 2004-2005 Nils Ohlmeier\n"); + printf(" report bugs to %s\n\n", PACKAGE_BUGREPORT); + printf( + " shoot : sipsak [-f FILE] [-L] -s SIPURI\n" + " trace : sipsak -T -s SIPURI\n" + " usrloc : sipsak -U [-I|M] [-b NUMBER] [-e NUMBER] [-x NUMBER] [-z NUMBER] -s SIPURI\n" + " usrloc : sipsak -I|M [-b NUMBER] [-e NUMBER] -s SIPURI\n" + " usrloc : sipsak -U [-C SIPURI] [-x NUMBER] -s SIPURI\n" + " message: sipsak -M [-B STRING] [-O STRING] [-c SIPURI] -s SIPURI\n" + " flood : sipsak -F [-e NUMBER] -s SIPURI\n" + " random : sipsak -R [-t NUMBER] -s SIPURI\n\n" + " additional parameter in every mode:\n" + ); + printf(" [-a PASSWORD] [-d] [-i] [-H HOSTNAME] [-l PORT] [-m NUMBER] [-n] " + "[-N]\n" + " [-r PORT] [-v] [-V] [-w]\n\n" + ); +} + +#ifdef HAVE_GETOPT_LONG +void print_long_help() { + print_version(); + printf( + " --help displays this help message\n" + " --version prints version string only\n" + " --filename=FILE the file which contains the SIP message to send\n" + " use - for standard input\n" + " --no-crlf de-activate CR (\\r) insertion\n" + " --sip-uri=SIPURI the destination server uri in form\n" + " sip:[user@]servername[:port]\n" + " --traceroute activates the traceroute mode\n" + ); + printf(" --usrloc-mode activates the usrloc mode\n" + " --invite-mode simulates a successful calls with itself\n" + " --message-mode sends messages to itself\n" + " --contact=SIPURI use the given uri as Contact in REGISTER\n" + " --appendix-begin=NUMBER the starting number appendix to the user name (default: 0)\n" + " --appendix-end=NUMBER the ending numer of the appendix to the user name\n" + " --sleep=NUMBER sleep number ms before sending next request\n" + ); + printf(" --expires=NUMBER the expires header field value (default: 15)\n" + " --remove-bindings=NUMBER activates randomly removing of user bindings\n" + " --flood-mode activates the flood mode\n" + " --random-mode activates the random modues (dangerous)\n" + " --trash-chars=NUMBER the maximum number of trashed character in random mode\n" + " (default: request length)\n" + ); + printf(" --local-port=PORT the local port to use (default: any)\n" + " --remote-port=PORT the remote port to use (default: 5060)\n" + " --outbound-proxy=HOSTNAME request target (outbound proxy)\n" + " --hostname=HOSTNAME overwrites the local hostname in all headers\n" + " --max-forwards=NUMBER the value for the max-forwards header field\n" +#ifdef OLDSTYLE_FQDN + " --numeric use IP instead of FQDN in the Via-Line\n" +#else + " --numeric use FQDN instead of IP in the Via-Line\n" +#endif +); + printf(" --processes=NUMBER Divide the workflow among the number of processes\n" + " --auth-username=STRING username for authentication\n" + ); + printf(" --no-via deactivate the insertion of a Via-Line\n" + " --password=PASSWORD password for authentication\n" + " (if omitted password=username)\n" + " --ignore-redirects ignore redirects\n" + " --verbose each v produces more verbosity (max. 3)\n" + " --extract-ip extract IP from the warning in reply\n" + " --replace-string=STRING replacement for a special mark in the message\n" + " --replace activates replacement of variables\n" + ); + printf(" --nagios-code returns exit codes Nagios compliant\n" + " --nagios-warn=NUMBER return Nagios warning if retrans > number\n" + " --message-body=STRING send a message with string as body\n" + " --disposition=STRING Content-Disposition value\n" + " --search=REGEXP search for a RegExp in replies and return error\n" + " on failfure\n" + " --timing=NUMBER number of test runs and print just the timings\n" + " --symmetric send and received on the same port\n" + " --from=SIPURI use the given uri as From in MESSAGE\n" + " --timeout-factor=NUMBER timeout multiplier for INVITE transactions\n" + " on non-reliable transports (default: 64)\n" + " --timer-t1=NUMBER timeout T1 in ms (default: %i)\n" + " --transport=STRING specify transport to be used\n" + " --headers=STRING adds additional headers to the request\n" + " --local-ip=STRING specify local ip address to be used\n" + " --authhash=STRING ha1 hash for authentication instead of password\n" + " --sylog=NUMBER log exit message to syslog with given log level\n" + , DEFAULT_TIMEOUT + ); +#ifdef WITH_TLS_TRANSP + printf(" --tls-ca-cert=FILE file with the cert of the root CA\n" + " --tls-client-cert=FILE file with the cert which sipsak will send\n" + " --tls-ignore-cert-failure ignore failures during the TLS handshake\n" + ); +#endif + exit_code(0, __PRETTY_FUNCTION__, NULL); +} +#endif + +/* prints out some usage help and exits */ +void print_help() { + print_version(); + printf( + " -h displays this help message\n" + " -V prints version string only\n" + " -f FILE the file which contains the SIP message to send\n" + " use - for standard input\n" + " -L de-activate CR (\\r) insertion in files\n" + " -s SIPURI the destination server uri in form\n" + " sip:[user@]servername[:port]\n" + " -T activates the traceroute mode\n" + " -U activates the usrloc mode\n" + " -I simulates a successful calls with itself\n" + " -M sends messages to itself\n" + ); + printf( + " -C SIPURI use the given uri as Contact in REGISTER\n" + " -b NUMBER the starting number appendix to the user name (default: 0)\n" + " -e NUMBER the ending numer of the appendix to the user name\n" + " -o NUMBER sleep number ms before sending next request\n" + " -x NUMBER the expires header field value (default: 15)\n" + " -z NUMBER activates randomly removing of user bindings\n" + " -F activates the flood mode\n" + ); + printf( + " -R activates the random modues (dangerous)\n" + " -t NUMBER the maximum number of trashed character in random mode\n" + " (default: request length)\n" + " -l PORT the local port to use (default: any)\n" + " -r PORT the remote port to use (default: 5060)\n" + " -p HOSTNAME request target (outbound proxy)\n" + ); + printf( + " -H HOSTNAME overwrites the local hostname in all headers\n" + " -m NUMBER the value for the max-forwards header field\n" +#ifdef OLDSTYLE_FQDN + " -n use IP instead of FQDN in the Via-Line\n" +#else + " -n use FQDN instead of IP in the Via-Line\n" +#endif + " -i deactivate the insertion of a Via-Line\n" + " -a PASSWORD password for authentication\n" + " (if omitted password=\"\")\n" + " -u STRING Authentication username\n" + ); + printf( + " -d ignore redirects\n" + " -v each v produces more verbosity (max. 3)\n" + " -w extract IP from the warning in reply\n" + " -g STRING replacement for a special mark in the message\n" + " -G activates replacement of variables\n" + " -N returns exit codes Nagios compliant\n" + " -q STRING search for a RegExp in replies and return error\n" + " on failure\n"); + printf(" -W NUMBER return Nagios warning if retrans > number\n" + " -B STRING send a message with string as body\n" + " -O STRING Content-Disposition value\n" + " -P NUMBER Number of processes to start\n" + " -A NUMBER number of test runs and print just timings\n" + " -S use same port for receiving and sending\n" + " -c SIPURI use the given uri as From in MESSAGE\n" + " -D NUMBER timeout multiplier for INVITE transactions\n" + " on non-reliable transports (default: 64)\n" + " -Z NUMBER timeout T1 in ms (default: %i)\n" + " -E STRING specify transport to be used\n" + " -j STRING adds additional headers to the request\n" + " -J STRING ha1 hash for authentication instead of password\n" + " -k STRING specify local ip address to be used\n" + " -K NUMBER log exit message to syslog with given log level\n" + , DEFAULT_TIMEOUT + ); + exit_code(0, __PRETTY_FUNCTION__, NULL); +} + +int main(int argc, char *argv[]) +{ + FILE *pf; + char buff[BUFSIZE]; + int c, i, port; + unsigned int tsp; + char *scheme, *user, *host, *backup; + pid_t pid; + struct timespec ts; + int upp; + +#ifdef HAVE_GETOPT_LONG + int option_index = 0; + static struct option l_opts[] = { + {"help", 0, 0, 0}, + {"version", 0, 0, 'V'}, + {"filename", 1, 0, 'f'}, + {"sip-uri", 1, 0, 's'}, + {"traceroute-mode", 0, 0, 'T'}, + {"usrloc-mode", 0, 0, 'U'}, + {"invite-mode", 0, 0, 'I'}, + {"message-mode", 0, 0, 'M'}, + {"contact", 1, 0, 'C'}, + {"appendix-begin", 1, 0, 'b'}, + {"appendix-end", 1, 0, 'e'}, + {"sleep", 1, 0, 'o'}, + {"expires", 1, 0, 'x'}, + {"remove-bindings", 1, 0, 'z'}, + {"flood-mode", 0, 0, 'F'}, + {"random-mode", 0, 0, 'R'}, + {"trash-chars", 1, 0, 't'}, + {"local-port", 1, 0, 'l'}, + {"remote-port", 1, 0, 'r'}, + {"outbound-proxy", 1, 0, 'p'}, + {"hostname", 1, 0, 'H'}, + {"max-fowards", 1, 0, 'm'}, + {"numeric", 0, 0, 'n'}, + {"no-via", 0, 0, 'i'}, + {"password", 1, 0, 'a'}, + {"ignore-redirects", 0, 0, 'd'}, + {"verbose", 0, 0, 'v'}, + {"extract-ip", 0, 0, 'w'}, + {"replace-string", 0, 0, 'g'}, + {"replace", 0, 0, 'G'}, + {"nagios-code", 0, 0, 'N'}, + {"nagios-warn", 1, 0, 'W'}, + {"search", 1, 0, 'q'}, + {"message-body", 1, 0, 'B'}, + {"disposition", 1, 0, 'O'}, + {"processes", 1, 0, 'P'}, + {"auth-username", 1, 0, 'u'}, + {"no-crlf", 0, 0, 'L'}, + {"timing", 1, 0, 'A'}, + {"symmetric", 0, 0, 'S'}, + {"from", 1, 0, 'c'}, + {"timeout-factor", 1, 0, 'D'}, + {"timer-t1", 1, 0, 'Z'}, + {"transport", 1, 0, 'E'}, + {"headers", 1, 0, 'j'}, + {"authhash", 1, 0, 'J'}, + {"local-ip", 1, 0, 'k'}, + {"syslog", 1, 0, 'K'}, +#ifdef WITH_TLS_TRANSP + {"tls-ca-cert", 1, 0, 0}, + {"tls-client-cert", 1, 0, 0}, + {"tls-ignore-cert-failure", 0, 0, 0}, +#endif + {0, 0, 0, 0} + }; +#endif + /* some initialisation to be safe */ + file_b=uri_b=trace=lport=usrloc=flood=verbose=randtrash=trashchar = 0; + warning_ext=rand_rem=nonce_count=replace_b=invite=message=sysl = 0; + sleep_ms=empty_contact=nagios_warn=timing=outbound_proxy=symmetric = 0; + namebeg=nameend=maxforw= -1; +#ifdef OLDSTYLE_FQDN + numeric = 0; +#else + numeric = 1; +#endif + via_ins=redirects=fix_crlf=processes = 1; + username=password=replace_str=hostname=contact_uri=mes_body = NULL; + con_dis=auth_username=from_uri=headers=authhash=local_ip = NULL; + scheme = user = host = backup = request = response = received = NULL; + regex = NULL; + address= 0; + transport=tsp = 0; + rport = port = 0; + expires_t = USRLOC_EXP_DEF; + timer_t1 = SIP_T1; + timer_t2 = 8; + timer_final = 64; + memset(buff, 0, BUFSIZE); + memset(fqdn, 0, FQDN_SIZE); +#ifdef WITH_TLS_TRANSP + cert_file = ca_file = NULL; + ignore_ca_fail = 0; +# ifdef USE_GNUTLS + tls_session = NULL; + xcred = NULL; +# else +# ifdef USE_OPENSSL + ctx = NULL; + ssl = NULL; +# endif +#endif +#endif /* WITH_TLS_TRANSP */ + + if (argc==1) { + print_help(); + } + + /* lots of command line switches to handle*/ +#ifdef HAVE_GETOPT_LONG + while ((c=getopt_long(argc, argv, "a:A:b:B:c:C:dD:e:E:f:Fg:GhH:iIj:J:k:K:l:Lm:MnNo:O:p:P:q:r:Rs:St:Tu:UvVwW:x:z:Z:", l_opts, &option_index)) != EOF){ +#else + while ((c=getopt(argc, argv, "a:A:b:B:c:C:dD:e:E:f:Fg:GhH:iIj:J:k:K:l:Lm:MnNo:O:p:P:q:r:Rs:St:Tu:UvVwW:x:z:Z:")) != EOF){ +#endif + switch(c){ +#ifdef HAVE_GETOPT_LONG + case 0: + printf("long option %s", l_opts[option_index].name); + if (optarg) { + printf(" with arg %s", optarg); + } + printf("\n"); + if (STRNCASECMP("help", l_opts[option_index].name, 4) == 0) { + print_long_help(); + } +#ifdef WITH_TLS_TRANSP + else if (STRNCASECMP("tls-ca-cert", l_opts[option_index].name, 11) == 0) { + pf = fopen(optarg, "rb"); + if (!pf){ + fprintf(stderr, "error: unable to open the CA cert file '%s'.\n", optarg); + exit_code(2, __PRETTY_FUNCTION__, "failed to open CA cert file"); + } + fclose(pf); + ca_file=optarg; + break; + } + else if (STRNCASECMP("tls-ignore-cert-failure", l_opts[option_index].name, 22) == 0) { + ignore_ca_fail = 1; + break; + } + else if (STRNCASECMP("tls-client-cert", l_opts[option_index].name, 14) == 0) { + pf = fopen(optarg, "rb"); + if (!pf){ + fprintf(stderr, "error: unable to open the client cert file '%s'.\n", optarg); + exit_code(2, __PRETTY_FUNCTION__, "failed to open client cert file"); + } + fclose(pf); + cert_file=optarg; + break; + } +#endif + break; +#endif + case 'a': + if (strlen(optarg) == 1 && STRNCASECMP(optarg, "-", 1) == 0) { + password = str_alloc(SIPSAK_MAX_PASSWD_LEN); + printf("Please enter the password (max. length %i): ", SIPSAK_MAX_PASSWD_LEN); + if (read_stdin(password, SIPSAK_MAX_PASSWD_LEN, 1) == 0) { + exit_code(0, __PRETTY_FUNCTION__, NULL); + } + } + else { + password=str_alloc(strlen(optarg) + 1); + strncpy(password, optarg, strlen(optarg)); + } + break; + case 'A': + timing=str_to_int(0, optarg); + break; + case 'b': + namebeg=str_to_int(0, optarg); + break; + case 'B': + mes_body=str_alloc(strlen(optarg) + 1); + strncpy(mes_body, optarg, strlen(optarg)); + break; + case 'c': + backup=str_alloc(strlen(optarg)+1); + strncpy(backup, optarg, strlen(optarg)); + parse_uri(backup, &scheme, &user, &host, &port); + if (scheme == NULL) { + fprintf(stderr, "error: missing scheme in From URI\n"); + exit_code(2, __PRETTY_FUNCTION__, "missing scheme in From URI"); + } + else if (user == NULL) { + fprintf(stderr, "error: missing username in From URI\n"); + exit_code(2, __PRETTY_FUNCTION__, "missing username in From URI"); + } + else if (host == NULL) { + fprintf(stderr, "error: missing host in From URI\n"); + exit_code(2, __PRETTY_FUNCTION__, "missing host in From URI"); + } + else { + from_uri=str_alloc(strlen(optarg)+1); + strncpy(from_uri, optarg, strlen(optarg)); + } + free(backup); + break; + case 'C': + if ((strlen(optarg) == 5 && STRNCASECMP(optarg, "empty", 5) == 0) || + (strlen(optarg) == 4 && STRNCASECMP(optarg, "none", 4) == 0)) { + empty_contact = 1; + } + else if ((strlen(optarg) == 1 && STRNCASECMP(optarg, "*", 1) == 0) || + (strlen(optarg) == 4 && STRNCASECMP(optarg, "star", 4) == 0)) { + contact_uri=str_alloc(2); + memcpy(contact_uri, "*", 1); + } + else { + backup=str_alloc(strlen(optarg)+1); + strncpy(backup, optarg, strlen(optarg)); + parse_uri(backup, &scheme, &user, &host, &port); + if (scheme == NULL) { + fprintf(stderr, "error: REGISTER Contact uri doesn't not contain " + "sip:, sips:, *, or is not empty\n"); + exit_code(2, __PRETTY_FUNCTION__, "unsupported Contact for registration"); + } + /*else if (user == NULL) { + fprintf(stderr, "error: missing username in Contact uri\n"); + exit_code(2); + }*/ + else if (host == NULL) { + fprintf(stderr, "error: missing host in Contact uri\n"); + exit_code(2, __PRETTY_FUNCTION__, "missing host in Contact"); + } + else { + contact_uri=str_alloc(strlen(optarg)+1); + strncpy(contact_uri, optarg, strlen(optarg)); + } + free(backup); + } + break; + case 'd': + redirects=0; + break; + case 'D': + timer_final = str_to_int(0, optarg); + if (timer_final <= 0) { + fprintf(stderr, "error: option D has to be above 0\n"); + exit_code(2, __PRETTY_FUNCTION__, "option D has to be above 0"); + } + break; + case 'e': + nameend=str_to_int(0, optarg); + break; + case 'E': + if (strlen(optarg) == 3 && + STRNCASECMP(optarg, "udp", 3) == 0) { + transport = SIP_UDP_TRANSPORT; + } + else if (strlen(optarg) == 3 && + STRNCASECMP(optarg, "tcp", 3) == 0) { + transport = SIP_TCP_TRANSPORT; + } +#ifdef WITH_TLS_TRANSP + else if (strlen(optarg) == 3 && + STRNCASECMP(optarg, "tls", 3) == 0) { + transport = SIP_TLS_TRANSPORT; + } +#endif + else { + fprintf(stderr, "error: unsupported transport '%s', supported values: udp, tcp\n", optarg); + exit_code(2, __PRETTY_FUNCTION__, "unsupported transport"); + } + break; + case 'F': + flood=1; + break; + case 'f': + if (strlen(optarg) != 1 && STRNCASECMP(optarg, "-", 1) != 0) { + /* file is opened in binary mode so that the cr-lf is + preserved */ + pf = fopen(optarg, "rb"); + if (!pf){ + fprintf(stderr, "error: unable to open the file '%s'.\n", optarg); + exit_code(2, __PRETTY_FUNCTION__, "failed to open file from the f option"); + } + if (fread(buff, 1, sizeof(buff), pf) >= sizeof(buff)){ + fprintf(stderr, "error:the file is too big. try files of less " + "than %i bytes.\n", BUFSIZE); + fprintf(stderr, " or recompile the program with bigger " + "BUFSIZE defined.\n"); + exit_code(2, __PRETTY_FUNCTION__, "file to big for buffer"); + } + fclose(pf); + } + else if (strlen(optarg) == 1 && STRNCASECMP(optarg, "-", 1) == 0) { + if (read_stdin(&buff[0], sizeof(buff), 0) == 0) { + exit_code(0, __PRETTY_FUNCTION__, NULL); + } + } + else { + fprintf(stderr, "error: unable to handle input file name: %s\n", optarg); + exit_code(2, __PRETTY_FUNCTION__, "unsupported input file name"); + } + file_b=1; + break; + case 'g': + replace_str=optarg; + break; + case 'G': + replace_b=1; + break; + case 'h': + print_help(); + break; + case 'H': + hostname=optarg; + break; + case 'i': + via_ins=0; + break; + case 'I': + invite=1; + break; + case 'j': + headers=optarg; + break; + case 'J': + if (strlen(optarg) < SIPSAK_HASHHEXLEN_MD5) { + fprintf(stderr, "error: authhash string is too short\n"); + exit_code(2, __PRETTY_FUNCTION__, "authhash string is too short"); + } + authhash=optarg; + break; + case 'k': + local_ip=optarg; + break; + case 'K': + sysl=str_to_int(0, optarg); + if (sysl < LOG_ALERT || sysl > LOG_DEBUG) { + fprintf(stderr, "error: syslog value '%s' must be between ALERT (1) and DEBUG (7)\n", optarg); + exit_code(2, __PRETTY_FUNCTION__, "unsupported syslog value for option K"); + } +#ifdef HAVE_SYSLOG_H + openlog(PACKAGE_NAME, LOG_CONS|LOG_NOWAIT|LOG_PID, LOG_USER); +#endif + break; + case 'l': + lport=str_to_int(0, optarg); + break; + case 'L': + fix_crlf=0; + break; + case 'm': + maxforw=str_to_int(0, optarg); + break; + case 'M': + message=1; + break; + case 'n': + numeric = 0; + break; + case 'N': + exit_mode=EM_NAGIOS; + break; + case 'o': + sleep_ms = 0; + if (strlen(optarg) == 4 && STRNCASECMP(optarg, "rand", 4) == 0) { + sleep_ms = -2; + } + else { + sleep_ms = str_to_int(0, optarg); + } + break; + case 'O': + con_dis=str_alloc(strlen(optarg) + 1); + strncpy(con_dis, optarg, strlen(optarg)); + break; + case 'p': + parse_uri(optarg, &scheme, &user, &host, &port); + if (host == NULL) { + fprintf(stderr, "error: missing in host in outbound proxy\n"); + exit_code(2, __PRETTY_FUNCTION__, "missing host in outbound proxy"); + } + if (is_ip(host)) { + address = getaddress(host); + if (transport == 0) + transport = SIP_UDP_TRANSPORT; + } + else { + if (!port) { + address = getsrvadr(host, &rport, &tsp); + if (tsp != 0) + transport = tsp; + } + if (!address) { + address = getaddress(host); + if (address && verbose > 1) + printf("using A record: %s\n", host); + } + if (!address){ + fprintf(stderr, "error:unable to determine the outbound proxy " + "address\n"); + exit_code(2, __PRETTY_FUNCTION__, "failed to resolve the outbound proxy"); + } + } + if (port && !rport) { + rport = port; + } + outbound_proxy=1; +#ifdef DEBUG + printf("address: %lu, rport: %i\n", address, rport); +#endif + break; + case 'P': + processes=str_to_int(0, optarg); + break; + case 'q': + if (regex) { + /* previously allocated -- free */ + regfree(regex); + } else { + /* never tried -- allocate */ + regex=malloc(sizeof(regex_t)); + }; + if (!regex) { + fprintf(stderr, "Error: can't allocate RE\n"); + exit_code(2, __PRETTY_FUNCTION__, "failed to allocate memory for regualr expression"); + }; + if (regcomp(regex, optarg, REG_EXTENDED|REG_ICASE|REG_NEWLINE )!=0) { + fprintf(stderr, "Error: compiling RE: %s\n", optarg ); + exit_code(2, __PRETTY_FUNCTION__, "failed to compile regular expression"); + }; + break; + case 'r': + port=str_to_int(0, optarg); + if (rport) { + fprintf(stderr, "warning: you are overwritting the destination port with the r argument\n"); + } + rport = port; + break; + case 'R': + randtrash=1; + break; + case 's': + parse_uri(optarg, &scheme, &user, &host, &port); + if (scheme == NULL) { + fprintf(stderr, "error: missing scheme in sip uri\n"); + exit_code(2, __PRETTY_FUNCTION__, "missing scheme in target SIP URI"); + } + if (strlen(optarg) == 4 && STRNCASECMP(optarg,"sips",4) == 0){ + fprintf(stderr, "error: sips is not supported yet\n"); + exit_code(2, __PRETTY_FUNCTION__, "unsupported scheme SIPS in target URI"); + } + else if (strlen(optarg) != 3 || STRNCASECMP(optarg,"sip",3) != 0){ + fprintf(stderr, "error: scheme of sip uri has to be sip\n"); + exit_code(2, __PRETTY_FUNCTION__, "unsupported scheme in target URI"); + } + if (user != NULL) { + username = user; + } + if (host != NULL) { + domainname = host; + } + else { + fprintf(stderr, "error: missing hostname in sip uri\n"); + exit_code(2, __PRETTY_FUNCTION__, "missing host name in target URI"); + } + if (port && !rport) { + rport = port; + } + if (is_ip(domainname) && !address) { + address = getaddress(domainname); + if (transport == 0) + transport = SIP_UDP_TRANSPORT; + } + else { + if (!rport && !address) { + address = getsrvadr(domainname, &rport, &tsp); + if (tsp != 0 && transport == 0) + transport = tsp; + } + if (!address) { + address = getaddress(domainname); + if (address && verbose > 1) + printf("using A record: %s\n", domainname); + } + if (!address){ + fprintf(stderr, "error:unable to determine the IP address for: %s\n", domainname); + exit_code(2, __PRETTY_FUNCTION__, "failed to resolve host from target URI"); + } + } + if (port != 0) { + backup = str_alloc(strlen(domainname)+1+6); + snprintf(backup, strlen(domainname)+6, "%s:%i", domainname, port); + domainname = backup; + } + uri_b=1; +#ifdef DEBUG + printf("address: %lu, rport: %i, username: '%s', domain: '%s'\n", address, rport, username, domainname); +#endif + break; + case 'S': + fprintf(stderr, "warning: symmetric does not work with a-symmetric servers\n"); + symmetric=1; + break; + case 't': + trashchar=str_to_int(0, optarg); + break; + case 'T': + trace=1; + break; + case 'U': + usrloc=1; + break; + case 'u': + auth_username=str_alloc(strlen(optarg) + 1); + strncpy(auth_username, optarg, strlen(optarg)); + break; + case 'v': + verbose++; + break; + case 'V': + printf("sipsak %s by Nils Ohlmeier\n Copyright (C) 2002-2004" + " FhG Fokus\n Copyright (C) 2004-2005 Nils Ohlmeier\n", + SIPSAK_VERSION); + printf(" compiled with DEFAULT_TIMEOUT=%i, FQDN_SIZE=%i", + DEFAULT_TIMEOUT, FQDN_SIZE); +#ifdef RAW_SUPPORT + printf(", RAW_SUPPORT"); +#endif +#ifdef HAVE_GETOPT_LONG + printf(", LONG_OPTS"); +#endif +#ifdef HAVE_FULL_OPENSSL + printf(", OPENSSL_MD5"); +#else + printf(", INTERNAL_MD5"); +#endif +#ifdef HAVE_OPENSSL_SHA1 + printf(", OPENSSL_SHA1"); +#endif +#ifdef WITH_TLS_TRANSP +# ifdef USE_GNUTLS + printf(", TLS_SUPPORT(GNUTLS)"); +# else +# ifdef USE_OPENSSL + printf(", TLS_SUPPORT(OPENSSL)"); +# endif +# endif +#endif +#ifdef HAVE_CARES_H + printf(", SRV_SUPPORT(ARES)"); +#else +# ifdef HAVE_RULI_H + printf(", SRV_SUPPORT(RULI)"); +# endif +#endif +#ifdef HAVE_STRCASESTR + printf(", STR_CASE_INSENSITIVE"); +#endif +#ifdef HAVE_STRNCASECMP + printf(", CMP_CASE_INSENSITIVE"); +#endif +#ifdef DEBUG + printf(", DEBUG"); +#endif + printf("\n"); + exit_code(0, __PRETTY_FUNCTION__, NULL); + break; + case 'w': + warning_ext=1; + break; + case 'W': + nagios_warn = str_to_int(0, optarg); + break; + case 'x': + expires_t=str_to_int(0, optarg); + break; + case 'z': + rand_rem=str_to_int(0, optarg); + if (rand_rem < 0 || rand_rem > 100) { + fprintf(stderr, "error: z option must between 0 and 100\n"); + exit_code(2, __PRETTY_FUNCTION__, "value for option z out of range"); + } + break; + case 'Z': + timer_t1 = str_to_int(0, optarg); + if (timer_t1 <= 0) { + fprintf(stderr, "error: Z option must be above 0\n"); + exit_code(2, __PRETTY_FUNCTION__, "value for option Z must be above 0"); + } + break; + default: + fprintf(stderr, "error: unknown parameter '%c'\n", c); + exit_code(2, __PRETTY_FUNCTION__, "unknown parameter"); + break; + } + } + + if (rport == 0) { + rport = 5060; + } + if (rport > 65535 || rport <= 0) { + fprintf(stderr, "error: invalid remote port: %i\n", rport); + exit_code(2, __PRETTY_FUNCTION__, "remote port out of range"); + } + if (transport == 0) { + transport = SIP_UDP_TRANSPORT; + } + + timer_t2 = timer_t2 * timer_t1; + timer_final = timer_final * timer_t1; + + /* replace LF with CRLF if we read from a file */ + if ((file_b) && (fix_crlf)) { + insert_cr(buff); + } + if (headers) { + backup = str_alloc(strlen(headers) + 30); // FIXME + strcpy(backup, headers); + headers = backup; + replace_string(headers, "\\n", "\r\n"); + backup = headers + strlen(headers) - 1; + if (*backup != '\n') { + strcpy(backup + 1, "\r\n"); + } + if (file_b) + insert_header(buff, headers, 1); + } + /* lots of conditions to check */ + if (trace) { + if (usrloc || flood || randtrash) { + fprintf(stderr, "error: trace can't be combined with usrloc, random or " + "flood\n"); + exit_code(2, __PRETTY_FUNCTION__, "trace mode can't be combined with other modes"); + } + if (!uri_b) { + fprintf(stderr, "error: for trace mode a SIPURI is really needed\n"); + exit_code(2, __PRETTY_FUNCTION__, "missing URI for trace mode"); + } + if (file_b) { + fprintf(stderr, "warning: file will be ignored for tracing."); + } + if (!username) { + fprintf(stderr, "error: for trace mode without a file the SIPURI have to " + "contain a username\n"); + exit_code(2, __PRETTY_FUNCTION__, "missing username in target URI"); + } + if (!via_ins){ + fprintf(stderr, "warning: Via-Line is needed for tracing. Ignoring -i\n"); + via_ins=1; + } + if (!warning_ext) { + fprintf(stderr, "warning: IP extract from warning activated to be more " + "informational\n"); + warning_ext=1; + } + if (maxforw==-1) maxforw=255; + } + else if (usrloc || invite || message) { + if (trace || flood || randtrash) { + fprintf(stderr, "error: usrloc can't be combined with trace, random or " + "flood\n"); + exit_code(2, __PRETTY_FUNCTION__, "usrloc mode can't be combined with other modes"); + } + if (!username || !uri_b) { + fprintf(stderr, "error: for the USRLOC mode you have to give a SIPURI with " + "a username\n at least\n"); + exit_code(2, __PRETTY_FUNCTION__, "missing target URI or username in URI"); + } + if (namebeg>0 && nameend==-1) { + fprintf(stderr, "error: if a starting numbers is given also an ending " + "number have to be specified\n"); + exit_code(2, __PRETTY_FUNCTION__, "missing end number"); + } + if (invite && message) { + fprintf(stderr, "error: invite and message tests are XOR\n"); + exit_code(2, __PRETTY_FUNCTION__, "INVITE and MESSAGE tests are XOR"); + } + if (!usrloc && invite && !lport) { + fprintf(stderr, "warning: Do NOT use the usrloc invite mode without " + "registering sipsak before.\n See man page for " + "details.\n"); + exit_code(2, __PRETTY_FUNCTION__, "don't use usrloc INVITE mode without registerting before"); + } + if (contact_uri!=NULL) { + if (invite || message) { + fprintf(stderr, "error: Contact uri is not support for invites or " + "messages\n"); + exit_code(2, __PRETTY_FUNCTION__, "Contact URI not supported for INVITE or MESSAGE mode"); + } + if (nameend!=-1 || namebeg!=-1) { + fprintf(stderr, "warning: ignoring starting or ending number if Contact" + " is given\n"); + nameend=namebeg=0; + } + if (rand_rem) { + fprintf(stderr, "warning: ignoring -z option when Contact is given\n"); + rand_rem=0; + } + } + if (via_ins) { + if (verbose > 1) { + fprintf(stderr, "warning: Deactivated Via insertion in usrloc mode.\n Please use option -i to suppress this warning.\n"); + } + via_ins=0; + } + if (nameend==-1) + nameend=0; + if (namebeg==-1) + namebeg=0; + } + else if (flood) { + if (trace || usrloc || randtrash) { + fprintf(stderr, "error: flood can't be combined with trace, random or " + "usrloc\n"); + exit_code(2, __PRETTY_FUNCTION__, "flood mode can't be combined with other modes"); + } + if (!uri_b) { + fprintf(stderr, "error: we need at least a sip uri for flood\n"); + exit_code(2, __PRETTY_FUNCTION__, "missing target URI"); + } + if (redirects) { + fprintf(stderr, "warning: redirects are not expected in flood. " + "disableing\n"); + redirects=0; + } + } + else if (randtrash) { + if (trace || usrloc || flood) { + fprintf(stderr, "error: random can't be combined with trace, flood or " + "usrloc\n"); + exit_code(2, __PRETTY_FUNCTION__, "random mode can't be combined with other modes"); + } + if (!uri_b) { + fprintf(stderr, "error: need at least a sip uri for random\n"); + exit_code(2, __PRETTY_FUNCTION__, "missing target URI"); + } + if (redirects) { + fprintf(stderr, "warning: redirects are not expected in random. " + "disableing\n"); + redirects=0; + } + if (verbose) { + fprintf(stderr, "warning: random characters may destroy your terminal " + "output\n"); + } + } + else if (mes_body) { + if (!message) { + fprintf(stderr, "warning: to send a message mode (-M) is required. activating\n"); + message=1; + } + if (!uri_b) { + fprintf(stderr, "error: need at least a sip uri to send a meesage\n"); + exit_code(2, __PRETTY_FUNCTION__, "missing target SIP URI"); + } + if (nameend==-1) + nameend=0; + if (namebeg==-1) + namebeg=0; + } + else { + if (!uri_b) { + fprintf(stderr, "error: a spi uri is needed at least\n"); + exit_code(2, __PRETTY_FUNCTION__, "missing target SIP URI"); + } + } + + switch (transport) { +#ifdef WITH_TLS_TRANSP + case SIP_TLS_TRANSPORT: + transport_str = TRANSPORT_TLS_STR; + break; +#endif /* WITH_TLS_TRANSP */ + case SIP_TCP_TRANSPORT: + transport_str = TRANSPORT_TCP_STR; + break; + case SIP_UDP_TRANSPORT: + transport_str = TRANSPORT_UDP_STR; + break; + default: + fprintf(stderr, "unknown transport: %u\n", transport); + exit_code(2, __PRETTY_FUNCTION__, "unknown transport"); + } + +#ifdef WITH_TLS_TRANSP + if (transport == SIP_TLS_TRANSPORT) { +# ifdef USE_GNUTLS + gnutls_global_init(); + //gnutls_anon_allocate_client_credentials(&anoncred); + gnutls_certificate_allocate_credentials(&xcred); + if (ca_file != NULL) { + // set the trusted CA file + gnutls_certificate_set_x509_trust_file(xcred, ca_file, GNUTLS_X509_FMT_PEM); + } +# else +# ifdef USE_OPENSSL + SSL_library_init(); + SSL_load_error_strings(); +# endif +# endif + } +#endif /* WITH_TLS_TRANSP */ + + /* determine our hostname */ + get_fqdn(); + + /* this is not a cryptographic random number generator, + but hey this is only a test-tool => should be satisfying*/ + srand(time(0) ^ (getpid() + (getpid() << 15))); + + if (processes > 1) { + if (signal(SIGCHLD , sigchld_handler) == SIG_ERR ) { + fprintf(stderr, "error: Could not install SIGCHLD handler\n"); + exit_code(2, __PRETTY_FUNCTION__, "failed to install SIGCHLD handler"); + } + } + + for(i = 0; i < processes - 1; i++) { + if ((pid = fork()) < 0) { + fprintf(stderr, "error: Cannot fork\n"); + exit_code(2, __PRETTY_FUNCTION__, "failed to fork"); + } + + if (pid == 0){ + /* child */ + upp = (nameend - namebeg + 1) / processes; + namebeg = namebeg + upp * i; + nameend = namebeg + upp; + shoot(&buff[0], sizeof(buff)); + } else { + if (lport) { + lport++; + } + } + + /* Delay execution of children so that the + * time of the first transmission gets spread over + * the retransmission interval evenly + */ + ts.tv_sec = 0; + ts.tv_nsec = (float)DEFAULT_TIMEOUT / (float)processes * (float)1000 * (float)1000; + nanosleep(&ts, 0); + } + + /* here we go...*/ + if (processes > 1) { + upp = (nameend - namebeg + 1) / processes; + namebeg = namebeg + upp * i; + nameend = namebeg + upp; + } + shoot(&buff[0], sizeof(buff)); + + /* normaly we won't come back here, but to satisfy the compiler */ + return 0; +} + diff -Nru sipsak-0.9.6+git20170713/src/sipsak.h sipsak-0.9.7/src/sipsak.h --- sipsak-0.9.6+git20170713/src/sipsak.h 1970-01-01 00:00:00.000000000 +0000 +++ sipsak-0.9.7/src/sipsak.h 2019-04-27 04:54:34.000000000 +0000 @@ -0,0 +1,340 @@ +/* + * Copyright (C) 2002-2004 Fhg Fokus + * Copyright (C) 2004-2005 Nils Ohlmeier + * + * This file belongs to sipsak, a free sip testing tool. + * + * sipsak is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * sipsak is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef SIPSAK_H +#define SIPSAK_H + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STDIO_H +# include +#endif +#ifdef HAVE_STDLIB_H +# include +#endif +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_REGEX_H +# include +#endif +#ifdef HAVE_SYS_PARAM_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifndef INET_ADDRSTRLEN +# define INET_ADDRSTRLEN 16 +#endif +#ifdef HAVE_SIGNAL_H +# include +#endif + +#ifdef HAVE_LIMITS_H +# include +#endif +#ifndef INT_MAX +# define INT_MAX 2147483648 +#endif + +#ifdef HAVE_STRCASESTR +# define __USE_GNU +# define STRCASESTR(s1,s2) strcasestr(s1,s2) +#else +# define STRCASESTR(s1,s2) strstr(s1,s2) +#endif +#ifdef HAVE_STRNCASECMP +# define STRNCASECMP(s1,s2,s3) strncasecmp(s1,s2,s3) +#else +# define STRNCASECMP(s1,s2,s3) strncmp(s1,s2,s3) +#endif +#ifdef HAVE_STRING_H +# include +#endif + +#ifdef HAVE_GNUTLS +# define USE_GNUTLS +# ifndef SIPSAK_NO_TLS +# define WITH_TLS_TRANSP 1 +# endif +# include +#else +# ifdef HAVE_OPENSSL_MD5_H +# ifdef HAVE_CRYPTO_WITH_MD5 +# define HAVE_FULL_OPENSSL +# define HAVE_EXTERNAL_MD5 +# define USE_OPENSSL +# include +# endif +# endif +#endif + +#ifdef HAVE_OPENSSL_SHA_H +# ifdef HAVE_CRYPTO_WITH_SHA1 +# define HAVE_OPENSSL_SHA1 +# endif +#endif + +#ifdef SIPSAK_PRINT_DBG +# define DEBUG 1 +#endif + +#ifndef REG_NOERROR +# define REG_NOERROR 0 +#endif + +#ifdef HAVE_SYS_PARAM_H +# ifdef MAXHOSTNAMELEN +# define FQDN_SIZE MAXHOSTNAMELEN + 1 +# else +# define FQDN_SIZE 100 +# endif +#else +# define FQDN_SIZE 100 +#endif + +#ifdef HAVE_CONFIG_H +# define SIP_T1 DEFAULT_TIMEOUT +#else +# define SIP_T1 500 +#endif + +#define SIP_T2 8*SIP_T1 + +#define SIPSAK_VERSION PACKAGE_VERSION +#define UA_VAL_STR "sipsak " SIPSAK_VERSION +#define BUFSIZE 4096 + +#define SIPSAK_MAX_PASSWD_LEN 20 + +#define REQ_REG 1 +#define REQ_REM 2 +#define REQ_INV 3 +#define REQ_MES 4 +#define REQ_OPT 5 +#define REQ_FLOOD 6 +#define REQ_RAND 7 + +#define SIP_TLS_TRANSPORT 1 +#define SIP_TCP_TRANSPORT 2 +#define SIP_UDP_TRANSPORT 3 + +#define TRANSPORT_TLS_STR "TLS" +#define TRANSPORT_TCP_STR "TCP" +#define TRANSPORT_UDP_STR "UDP" +#define TRANSPORT_STR_LEN 3 + +#define VIA_SIP_STR "Via: SIP/2.0/" +#define VIA_SIP_STR_LEN (sizeof(VIA_SIP_STR) - 1) + +#define SIP20_STR " SIP/2.0\r\n" +#define SIP20_STR_LEN (sizeof(SIP20_STR) - 1) + +#define SIP200_STR "SIP/2.0 200 OK\r\n" +#define SIP200_STR_LEN (sizeof(SIP200_STR) - 1) + +#define INV_STR "INVITE" +#define INV_STR_LEN (sizeof(INV_STR) - 1) + +#define REG_STR "REGISTER" +#define REG_STR_LEN (sizeof(REG_STR) - 1) + +#define OPT_STR "OPTIONS" +#define OPT_STR_LEN (sizeof(OPT_STR) - 1) + +#define MES_STR "MESSAGE" +#define MES_STR_LEN (sizeof(MES_STR) - 1) + +#define ACK_STR "ACK" +#define ACK_STR_LEN (sizeof(ACK_STR) - 1) + +#define FROM_STR "From: " +#define FROM_STR_LEN (sizeof(FROM_STR) - 1) +#define FROM_SHORT_STR "\nf: " +#define FROM_SHORT_STR_LEN (sizeof(FROM_SHORT_STR) - 1) + +#define TO_STR "To: " +#define TO_STR_LEN (sizeof(TO_STR) - 1) +#define TO_SHORT_STR "\nt: " +#define TO_SHORT_STR_LEN (sizeof(TO_SHORT_STR) - 1) + +#define VIA_STR "Via: " +#define VIA_STR_LEN (sizeof(VIA_STR) - 1) +#define VIA_SHORT_STR "\nv: " +#define VIA_SHORT_STR_LEN (sizeof(VIA_SHORT_STR) - 1) + +#define CALL_STR "Call-ID: " +#define CALL_STR_LEN (sizeof(CALL_STR) - 1) +#define CALL_SHORT_STR "\ni: " +#define CALL_SHORT_STR_LEN (sizeof(CALL_SHORT_STR) - 1) + +#define MAX_FRW_STR "Max-Forwards: " +#define MAX_FRW_STR_LEN (sizeof(MAX_FRW_STR) - 1) + +#define CSEQ_STR "CSeq: " +#define CSEQ_STR_LEN (sizeof(CSEQ_STR) - 1) + +#define CONT_STR "Contact: " +#define CONT_STR_LEN (sizeof(CONT_STR) - 1) +#define CONT_SHORT_STR "\nm: " +#define CONT_SHORT_STR_LEN (sizeof(CONT_SHORT_STR) - 1) + +#define CON_TYP_STR "Content-Type: " +#define CON_TYP_STR_LEN (sizeof(CON_TYP_STR) - 1) +#define CON_TYP_SHORT_STR "\nc: " +#define CON_TYP_SHORT_STR_LEN (sizeof(CON_TYP_SHORT_STR) - 1) + +#define CON_DIS_STR "Content-Disposition: " +#define CON_DIS_STR_LEN (sizeof(CON_DIS_STR) - 1) + +#define TXT_PLA_STR "text/plain" +#define TXT_PLA_STR_LEN (sizeof(TXT_PLA_STR) - 1) + +#define ACP_STR "Accept: " +#define ACP_STR_LEN (sizeof(ACP_STR) - 1) + +#define CON_LEN_STR "Content-Length: " +#define CON_LEN_STR_LEN (sizeof(CON_LEN_STR) - 1) +#define CON_LEN_SHORT_STR "\nl: " +#define CON_LEN_SHORT_STR_LEN (sizeof(CON_LEN_SHORT_STR) - 1) + +#define RR_STR "Record-Route: " +#define RR_STR_LEN (sizeof(RR_STR) - 1) + +#define ROUTE_STR "Route: " +#define ROUTE_STR_LEN (sizeof(ROUTE_STR) - 1) + +#define SIPSAK_MES_STR "test message from SIPsak for user " +#define SIPSAK_MES_STR_LEN (sizeof(SIPSAK_MES_STR) - 1) + +#define EXP_STR "Expires: " +#define EXP_STR_LEN (sizeof(EXP_STR) - 1) + +#define CON_EXP_STR "expires=" +#define CON_EXP_STR_LEN (sizeof(CON_EXP_STR) - 1) + +#define WWWAUTH_STR "WWW-Authenticate: " +#define WWWAUTH_STR_LEN (sizeof(WWWAUTH_STR) - 1) + +#define PROXYAUTH_STR "Proxy-Authenticate: " +#define PROXYAUTH_STR_LEN (sizeof(PROXYAUTH_STR) - 1) + +#define AUTH_STR "Authorization: Digest " +#define AUTH_STR_LEN (sizeof(AUTH_STR) - 1) + +#define PROXYAUZ_STR "Proxy-Authorization: Digest " +#define PROXYAUZ_STR_LEN (sizeof(PROXYAUZ_STR) - 1) + +#define ALGO_STR "algorithm=" +#define ALGO_STR_LEN (sizeof(ALGO_STR) - 1) + +#define MD5_STR "MD5, " +#define MD5_STR_LEN (sizeof(MD5_STR) - 1) + +#define SHA1_STR "SHA1, " +#define SHA1_STR_LEN (sizeof(SHA1_STR) - 1) + +#define SHA256_STR "SHA-256, " +#define SHA256_STR_LEN (sizeof(SHA256_STR) - 1) + +#define REALM_STR "realm=" +#define REALM_STR_LEN (sizeof(REALM_STR) - 1) + +#define OPAQUE_STR "opaque=" +#define OPAQUE_STR_LEN (sizeof(OPAQUEE_STR) - 1) + +#define NONCE_STR "nonce=" +#define NONCE_STR_LEN (sizeof(NONCE_STR) - 1) + +#define RESPONSE_STR "response=" +#define RESPONSE_STR_LEN (sizeof(RESPONSE_STR) - 1) + +#define QOP_STR "qop=" +#define QOP_STR_LEN (sizeof(QOP_STR) - 1) + +#define QOPAUTH_STR "auth" +#define QOPAUTH_STR_LEN (sizeof(QOPAUTH_STR) - 1) + +#define NC_STR "nc=" +#define NC_STR_LEN (sizeof(NC_STR) - 1) + +#define EMPTY_STR "" +#define EMPTY_STR_LEN (sizeof(EMPTY_STR) - 1) + +#define UA_STR "User-Agent: " +#define UA_STR_LEN (sizeof(UA_STR) - 1) + +#define SUB_STR "Subject: " +#define SUB_STR_LEN (sizeof(SUB_STR) - 1) + +#define SIP100_STR "SIP/2.0 100" +#define SIP100_STR_LEN (sizeof(SIP100_STR) - 1) + +#define TRANSPORT_PARAMETER_STR ";transport=" +#define TRANSPORT_PARAMETER_STR_LEN (sizeof(TRANSPORT_PARAMETER_STR) - 1) + +#define USRLOC_EXP_DEF 15 +#define FLOOD_METH "OPTIONS" + +#define SIPSAK_HASHLEN_MD5 16 +#define SIPSAK_HASHHEXLEN_MD5 2 * SIPSAK_HASHLEN_MD5 +#ifdef HAVE_OPENSSL_SHA1 +# define SIPSAK_HASHLEN_SHA1 20 +# define SIPSAK_HASHHEXLEN_SHA1 2 * SIPSAK_HASHLEN_SHA1 +# define SIPSAK_HASHLEN_SHA256 32 +# define SIPSAK_HASHHEXLEN_SHA256 2 * SIPSAK_HASHLEN_SHA256 +# define SIPSAK_HASHLEN SIPSAK_HASHLEN_SHA256 +#else +# define SIPSAK_HASHLEN SIPSAK_HASHLEN_MD5 +#endif +#define SIPSAK_HASHHEXLEN 2 * SIPSAK_HASHLEN + +#ifdef WITH_TLS_TRANSP +char *cert_file, *ca_file; +int ignore_ca_fail; +# ifdef USE_GNUTLS +gnutls_session_t tls_session; +//gnutls_anon_client_credentials_t anoncred; +gnutls_certificate_credentials_t xcred; +# else +# ifdef USE_OPENSSL +SSL_CTX* ctx; +SSL* ssl; +# endif +# endif +#endif + +/* lots of global variables. ugly but makes life easier. */ +unsigned long address; +unsigned int nonce_count, transport; +int sleep_ms, processes, cseq_counter; +int verbose, nameend, namebeg, expires_t, flood, warning_ext, invite, message; +int maxforw, lport, rport, randtrash, trashchar, numeric, symmetric; +int file_b, uri_b, trace, via_ins, usrloc, redirects, rand_rem, replace_b; +int empty_contact, nagios_warn, fix_crlf, timing, outbound_proxy; +int timer_t1, timer_t2, timer_final, sysl; +char *username, *domainname, *password, *replace_str, *hostname, *contact_uri; +char *mes_body, *con_dis, *auth_username, *from_uri, *headers, *authhash, *local_ip; +char fqdn[FQDN_SIZE]; +char target_dot[INET_ADDRSTRLEN], source_dot[INET_ADDRSTRLEN]; +char *request, *response, *received, *transport_str; +regex_t* regex; + +#endif diff -Nru sipsak-0.9.6+git20170713/src/transport.c sipsak-0.9.7/src/transport.c --- sipsak-0.9.6+git20170713/src/transport.c 1970-01-01 00:00:00.000000000 +0000 +++ sipsak-0.9.7/src/transport.c 2019-04-27 04:54:34.000000000 +0000 @@ -0,0 +1,1238 @@ +/* + * Copyright (C) 2005 Nils Ohlmeier + * + * This file belongs to sipsak, a free sip testing tool. + * + * sipsak is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * sipsak is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "sipsak.h" + +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else +# ifdef HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif /* TIME_WITH_SYS_TIME */ +#ifdef HAVE_UNISTD_H +# ifdef HAVE_SYS_TYPES_H +# include +# endif +# include +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_SYS_POLL_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif + +#include "transport.h" +#include "shoot.h" + +#ifdef RAW_SUPPORT +# ifdef HAVE_NETINET_IN_SYSTM_H +# include +# endif +# ifdef HAVE_NETINET_IP_H +# include +# endif +# ifdef HAVE_NETINET_IP_ICMP_H +# include +# endif +# ifdef HAVE_NETINET_UDP_H +# define __FAVOR_BSD +# include +# endif +#endif /* RAW_SUPPORT */ + +#ifdef WITH_TLS_TRANSP +# ifdef USE_GNUTLS +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# else +# ifdef USE_OPENSSL +# define _BSD_SOURCE 1 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# endif +# endif +#endif /* WITH_TLS_TRANSP */ + +#include "exit_code.h" +#include "helper.h" +#include "header_f.h" + +#ifdef RAW_SUPPORT +int rawsock; +#endif + +#ifdef WITH_TLS_TRANSP +# ifdef USE_GNUTLS +void check_alert(gnutls_session_t session, int ret) { + int last_alert; + + if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED || + ret == GNUTLS_E_FATAL_ALERT_RECEIVED) { + last_alert = gnutls_alert_get(session); + printf("Received TLS alert: '%d': %s\n", last_alert, + gnutls_alert_get_name(last_alert)); + } +} + +/* all the available CRLs */ +gnutls_x509_crl_t *global_crl_list; +int global_crl_list_size; + +/* all the available trusted CAs */ +gnutls_x509_crt_t *global_ca_list; +int global_ca_list_size; + +/* verifies a certificate against an other certificate which is supposed to + * be it's issuer. Also checks the crl_list of the certificate is revoked. + */ +static void verify_cert2(gnutls_x509_crt_t crt, gnutls_x509_crt_t issuer, + gnutls_x509_crl_t *crl_list, int crl_list_size) { + unsigned int output; + time_t now = time(0); + size_t name_size; + char name[64]; + + /* print information about the certificates to be checked */ + name_size = sizeof(name); + gnutls_x509_crt_get_dn(crt, name, &name_size); + + printf("Certificate: %s\n", name); + + name_size = sizeof(name); + gnutls_x509_crt_get_issuer_dn(crt, name, &name_size); + + printf("Issued by: %s\n", name); + + /* Get the DN of the issuer cert. */ + name_size = sizeof(name); + gnutls_x509_crt_get_dn(issuer, name, &name_size); + + printf("Checking against: %s\n", name); + + /* Do the actual verification */ + gnutls_x509_crt_verify(crt, &issuer, 1, 0, &output); + + if (output & GNUTLS_CERT_INVALID) { + printf("Certificate not trusted!!!"); + if (output & GNUTLS_CERT_SIGNER_NOT_FOUND) { + printf(": no issuer was found\n"); + } + if (output & GNUTLS_CERT_SIGNER_NOT_CA) { + printf(": issuer is not a CA\n"); + } + } + else { + printf("Certificate trusted'n"); + } + + /* Now check the expiration dates */ + if (gnutls_x509_crt_get_activation_time(crt) > now) { + printf("Certificate not yet activated!\n"); + } + if (gnutls_x509_crt_get_expiration_time(crt) < now) { + printf("Certificate expired!\n"); + } + /* Check if the certificate is revoked */ + if (gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size) == 1) { + printf("Certificate is revoked!\n"); + } +} + +/* Verifies a certificate against our trusted CA list. Also checks the crl_list + * if the certificate is revoked + */ +static void verify_last_cert(gnutls_x509_crt_t crt, gnutls_x509_crt_t *ca_list, + int ca_list_size, gnutls_x509_crl_t *crl_list, int crl_list_size) { + unsigned int output; + time_t now = time(0); + size_t name_size; + char name[64]; + + /* Print information about the certificates to be checked */ + name_size = sizeof(name); + gnutls_x509_crt_get_dn(crt, name, &name_size); + printf("Certificate: %s\n", name); + + name_size = sizeof(name); + gnutls_x509_crt_get_issuer_dn(crt, name, &name_size); + printf("Issued by: %s\n", name); + + /* Do the actual verification */ + gnutls_x509_crt_verify(crt, ca_list, ca_list_size, + GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT, &output); + if (output & GNUTLS_CERT_INVALID) { + printf("Certificate not truested!\n"); + if (output & GNUTLS_CERT_SIGNER_NOT_CA) { + printf(": Issuer is not a CA\n"); + } + } + else { + printf("Certificate trusted\n"); + } + + /* Now check the expiration dates */ + if (gnutls_x509_crt_get_activation_time(crt) > now) { + printf("Certificate now yet activated!\n"); + } + if (gnutls_x509_crt_get_expiration_time(crt) < now) { + printf("Certificate expired!\n"); + } + /* Check of the vertificate is revoked */ + if (gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size) == 1) { + printf("Certificate is revoked!\n"); + } +} + +/* this function will try yo verify the peer's certificate chain, ans + * also check if the hostname matches, and the activation and expiration dates. + */ +void verify_certificate_chain(gnutls_session_t session, const char *hostname, + const gnutls_datum_t *cert_chain, int cert_chain_length) { + int i; + gnutls_x509_crt_t *cert; + + cert = malloc(sizeof(*cert) * cert_chain_length); + if (!cert) { + printf("gnutla: failed to allocate memory for cert chain verification'n"); + return; + } + + /* import all the certificates in the chain to native certificate format */ + for (i = 0; i < cert_chain_length; i++) { + gnutls_x509_crt_init(&cert[i]); + gnutls_x509_crt_import(cert[i], &cert_chain[i], GNUTLS_X509_FMT_DER); + } + + /* if the last certificate in the chain is seld signed ignore it. + * that is because we want to check against our trusted certificate list + */ + if (gnutls_x509_crt_check_issuer(cert[cert_chain_length - 1], + cert[cert_chain_length -1]) > 0 && cert_chain_length > 0) { + cert_chain_length--; + } + /* now verify the certificates against other issuers in the chain */ + for (i = 1; i < cert_chain_length; i++) { + verify_cert2(cert[i - 1], cert[i], global_crl_list, global_crl_list_size); + } + /* here we must verify the last certificate in the chain against our + * trusted CA list + */ + verify_last_cert(cert[cert_chain_length - 1], global_ca_list, + global_ca_list_size, global_crl_list, global_crl_list_size); + /* check if the name in the first certificate matches our destination */ + if (!gnutls_x509_crt_check_hostname(cert[0], hostname)) { + printf("The certificate's owner does not match hostname '%s'\n", + hostname); + } + + for (i = 0; i < cert_chain_length; i++) { + gnutls_x509_crt_deinit(cert[i]); + } + return; +} + +int verify_certificate_simple(gnutls_session_t session, const char *hostname) { + unsigned int status, cert_list_size; + const gnutls_datum_t *cert_list; + int ret; + gnutls_x509_crt_t cert; + + // this verification function usese the trusted CAs in the credentials + // structure. so you must have installed on or more CA certificates. + ret = gnutls_certificate_verify_peers2(session, &status); + + if (ret < 0) { + printf("gnutls verify peer failed.\n"); + return -1; + } + ret = 0; + + if (status & GNUTLS_CERT_INVALID) { + ret |= -2; + printf("The certificate is not trustworthy\n"); + if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) { + printf("The certificate hasn't got a known issuer.\n"); + ret |= -4; + } + if (status & GNUTLS_CERT_SIGNER_NOT_CA) { + printf("The certificate issuer is not a CA\n"); + ret |= -8; + } + } + if (status & GNUTLS_CERT_REVOKED) { + printf("The certificate has beend revoked.\n"); + ret = -16; + } + if (ret != 0 && ignore_ca_fail == 0) { + return ret; + } + + // from here on it works only with X509 certs + if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509){ + printf("The server certificate is not X509.\n"); + return -32;; + } + if (gnutls_x509_crt_init(&cert) < 0) { + printf("gnutls crt init failed.\n"); + return -64; + } + + cert_list = gnutls_certificate_get_peers(session, &cert_list_size); + if (cert_list == NULL) { + printf("gnutls did not found a server certificate.\n"); + return -128; + } + + // this not a real world check as only the first cert is checked! + if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER)) { + printf("gnutls failed to parse server certificate.\n"); + return -256; + } + + // beware here we do not check for errors + if (gnutls_x509_crt_get_expiration_time(cert) < time(0)) { + printf("The server certificate is expired.\n"); + return -512; + } + if (gnutls_x509_crt_get_activation_time(cert) > time(0)) { + printf("The server certificate is not yet activated.\n"); + return -1024; + } + if (!gnutls_x509_crt_check_hostname(cert, hostname)) { + printf("The server certificate's owner does not match hostname '%s'\n", + hostname); + return -2048; + } + + gnutls_x509_crt_deinit(cert); + + return ret; +} + +static const char *bin2hex(const void *bin, size_t bin_size) { + static char printable[110]; + const unsigned char *_bin = bin; + char *print; + size_t i; + + if (bin_size > 50) { + bin_size = 50; + } + + print = printable; + for (i=0; i < bin_size; i++) { + sprintf(print, "%.2x ", _bin[i]); + print += 2; + } + + return printable; +} + +void print_x509_certificate_info(gnutls_session_t session) { + char serial[40]; + char dn[128]; + size_t size; + unsigned int algo, bits; + time_t expiration_time, activation_time; + const gnutls_datum_t *cert_list; + unsigned int cert_list_size = 0; + gnutls_x509_crt_t cert; + + // check if we got a X.509 cert + if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) { + printf("TLS session did not received a X.509 certificate\n"); + return; + } + + cert_list = gnutls_certificate_get_peers(session, &cert_list_size); + printf("Peer provided %u certificate(s)\n", cert_list_size); + + if (cert_list_size > 0) { + // print only informations about the first cert + gnutls_x509_crt_init(&cert); + gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER); + printf("Certificate info:\n"); + activation_time = gnutls_x509_crt_get_activation_time(cert); + printf("\tCertificate is valid since: %s", ctime(&activation_time)); + expiration_time = gnutls_x509_crt_get_expiration_time(cert); + printf("\tCertificate expires: %s", ctime(&expiration_time)); + // print the serial number of the certificate + size = sizeof(serial); + gnutls_x509_crt_get_serial(cert, serial, &size); + printf("\tCertificate serail number: %s\n", bin2hex(serial, size)); + // extract public key algorithm + algo = gnutls_x509_crt_get_pk_algorithm(cert, &bits); + printf("\tCertificate public key algorithm: %s\n", gnutls_pk_algorithm_get_name(algo)); + // print version of x509 cert + printf("\tCertificate version: #%d\n", gnutls_x509_crt_get_version(cert)); + // print name of the certificate + size = sizeof(dn); + gnutls_x509_crt_get_dn(cert, dn, &size); + printf("\tDN: %s\n", dn); + // print subject alt name of the certificate + size = sizeof(dn); + if (gnutls_x509_crt_get_subject_alt_name(cert, 0, dn, &size, NULL) == 0) { + printf("\tSubject Alt Name: %s\n", dn); + } + // print the algorithm which was used for signing the cert + algo = gnutls_x509_crt_get_signature_algorithm(cert); + printf("\tCA's signature algorithm: %s\n", gnutls_pk_algorithm_get_name(algo)); + // print the name of the CA + size = sizeof(dn); + if (gnutls_x509_crt_get_issuer_dn(cert, dn, &size) == 0) { + printf("\tCA's DN: %s\n", dn); + } + // print the CA status flags if present + if (gnutls_x509_crt_get_ca_status(cert, &algo) > 0 && algo != 0) { + printf("\tCA status flag is set\n"); + } + // print the fingerprint of the cert + size = sizeof(dn); + // FIXME + if (gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, dn, &size) == 0) { + printf("\tFingerprint of the certificate: %s\n", dn); + } + + + gnutls_x509_crt_deinit(cert); + } +} + +void gnutls_session_info(gnutls_session_t session) { + const char *tmp; + gnutls_credentials_type_t cred; + gnutls_kx_algorithm_t kx; + + // print the key exchange algorithm name + kx = gnutls_kx_get(session); + tmp = gnutls_kx_get_name(kx); + printf("Key Echange: %s\n", tmp); + + // check the authentication type + cred = gnutls_auth_get_type(session); + switch(cred) { +#ifdef HAVE_GNUTLS_SRP + case GNUTLS_CRD_SRP: + printf("SRP session with username %s\n", + gnutls_srp_server_get_username(session)); + break; +#endif // HAVE_GNUTLS_SRP + case GNUTLS_CRD_ANON: + printf("Anonymous DH using prime of %d bits\n", + gnutls_dh_get_prime_bits(session)); + break; + case GNUTLS_CRD_CERTIFICATE: + // check if we have been using ephemeral DH + if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS) { + printf("Emphemeral DH using prime of %d bits\n", + gnutls_dh_get_prime_bits(session)); + } + // print certificate informations if available + print_x509_certificate_info(session); + break; + default: + printf("UNKNOWN GNUTLS authentication type!!!\n"); + } + + // print protocols name + tmp = gnutls_protocol_get_name(gnutls_protocol_get_version(session)); + printf("Protocol: %s\n", tmp); + + // print certificate type + tmp = gnutls_certificate_type_get_name(gnutls_certificate_type_get(session)); + printf("Certificate Type: %s\n", tmp); + + // print the compression algorithm + tmp = gnutls_compression_get_name(gnutls_compression_get(session)); + printf("Compression: %s\n", tmp); + + // print name of the cipher + tmp = gnutls_cipher_get_name(gnutls_cipher_get(session)); + printf("Cipher: %s\n", tmp); + + // print the MAC algorithm + tmp = gnutls_mac_get_name(gnutls_mac_get(session)); + printf("MAC: %s\n", tmp); +} +# else +# ifdef USE_OPENSSL +void set_tls_options() { +#if OPENSSL_VERSION_NUMBER >= 0x0009070000 /* 0.9.7 */ + SSL_CTX_set_options(ctx, SSL_OP_ALL | + SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | + SSL_OP_CIPHER_SERVER_PREFERENCE); +#else + SSL_CTX_set_options(ctx, SSL_OP_ALL); +#endif +} + +void create_tls_ctx() { + SSL_METHOD *method = NULL; + + method = TLSv1_method(); + ctx = SSL_CTX_new(method); + if (ctx == NULL) { + ERR_print_errors_fp(stderr); + perror("create_tls_ctx: failed to create TLS ctx"); + exit_code(2, __PRETTY_FUNCTION__, "failed to create TLS ctx"); + } + /*if (!SSL_CTX_use_certificate_chain_file(ctx, cert_file)) { + perror("create_tls_ctx: failed to load certificate file"); + exit_code(2); + } + if (SSL_CTX_load_verify_locations(ctx, ca_file, 0) != 1) { + perror("create_tls_ctx: failed to load CA cert"); + exit_code(2); + } + SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(ca_file)); + if (SSL_CTX_get_client_CA_list(ctx) == 0) { + perror("create_tls_ctx: failed to set client CA list"); + exit_code(2); + }*/ + SSL_CTX_set_cipher_list(ctx, 0); + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0); + SSL_CTX_set_verify_depth(ctx, 5); + set_tls_options(); + SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); + SSL_CTX_set_session_id_context(ctx, 0, 0); +} + +void tls_dump_cert_info(char* s, X509* cert) { + char *subj, *issuer; + + subj = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); + issuer = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); + + printf("%s subject: '%s'\n", s ? s: "", subj); + printf("%s issuer: '%s'\n", s ? s : "", issuer); + OPENSSL_free(subj); + OPENSSL_free(issuer); +} +# endif /* USE_OPENSSL */ +# endif /* USE_GNUTLS */ +#endif /* WITH_TLS_TRANSP */ + +void create_sockets(struct sipsak_con_data *cd) { + socklen_t slen; + +#ifdef RAW_SUPPORT + rawsock = -1; +#endif + + memset(&(cd->adr), 0, sizeof(struct sockaddr_in)); + cd->adr.sin_family = AF_INET; + if(local_ip) { + cd->adr.sin_addr.s_addr = inet_addr(local_ip); + } else { + cd->adr.sin_addr.s_addr = htonl( INADDR_ANY); + } + cd->adr.sin_port = htons((short)lport); + + if (transport == SIP_UDP_TRANSPORT) { + /* create the un-connected socket */ + if (!symmetric) { + cd->usock = (int)socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (cd->usock==-1) { + perror("unconnected UDP socket creation failed"); + exit_code(2, __PRETTY_FUNCTION__, "failed to create unconnected UDP socket"); + } + if (bind(cd->usock, (struct sockaddr *) &(cd->adr), sizeof(struct sockaddr_in) )==-1) { + perror("unconnected UDP socket binding failed"); + exit_code(2, __PRETTY_FUNCTION__, "failed to bind unconnected UDP socket"); + } + } + + +#ifdef RAW_SUPPORT + /* try to create the raw socket */ + rawsock = (int)socket(PF_INET, SOCK_RAW, IPPROTO_ICMP); + if (rawsock==-1) { + if (verbose>1) + fprintf(stderr, "warning: need raw socket (root privileges) to receive all ICMP errors\n"); +#endif + /* create the connected socket as a primitve alternative to the + raw socket*/ + cd->csock = (int)socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (cd->csock==-1) { + perror("connected UDP socket creation failed"); + exit_code(2, __PRETTY_FUNCTION__, "failed to create connected UDP socket"); + } + + if (!symmetric) + cd->adr.sin_port = htons((short)0); + if (bind(cd->csock, (struct sockaddr *) &(cd->adr), sizeof(struct sockaddr_in) )==-1) { + perror("connected UDP socket binding failed"); + exit_code(2, __PRETTY_FUNCTION__, "failed to bind connected UDP socket"); + } +#ifdef RAW_SUPPORT + } + else if (symmetric) { + cd->csock = (int)socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (cd->csock==-1) { + perror("connected UDP socket creation failed"); + exit_code(2, __PRETTY_FUNCTION__, "failed to create connected UDP socket"); + } + if (bind(cd->csock, (struct sockaddr *) &(cd->adr), sizeof(struct sockaddr_in) )==-1) { + perror("connected UDP socket binding failed"); + exit_code(2, __PRETTY_FUNCTION__, "failed to bind connected UDP socket"); + } + } +#endif + } + else { + cd->csock = (int)socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (cd->csock==-1) { + perror("TCP socket creation failed"); + exit_code(2, __PRETTY_FUNCTION__, "failed to create TCP socket"); + } + if (bind(cd->csock, (struct sockaddr *) &(cd->adr), sizeof(struct sockaddr_in) )==-1) { + perror("TCP socket binding failed"); + exit_code(2, __PRETTY_FUNCTION__, "failed to bind TCP socket"); + } +#ifdef WITH_TLS_TRANSP + if (transport == SIP_TLS_TRANSPORT) { +#ifdef USE_GNUTLS + // initialixe the TLS session + gnutls_init(&tls_session, GNUTLS_CLIENT); + // use default priorities + gnutls_set_default_priority(tls_session); + // put the X509 credentials to the session + gnutls_credentials_set(tls_session, GNUTLS_CRD_CERTIFICATE, xcred); + // add the FD to the session +# ifdef HAVE_GNUTLS_319 + gnutls_transport_set_int(tls_session, cd->csock); +# else + gnutls_transport_set_ptr(tls_session, (gnutls_transport_ptr_t)(intptr_t)cd->csock); +# endif +#else /* USE_GNUTLS */ +# ifdef USE_OPENSSL + create_tls_ctx(); + ssl = SSL_new(ctx); + if (ssl == NULL) { + perror("TLS failed to create SSL object"); + exit_code(2, __PRETTY_FUNCTION__, "failed to create SSL object"); + } + if (SSL_set_fd(ssl, cd->csock) != 1) { + perror("TLS failed to add socket to SSL object"); + exit_code(2, __PRETTY_FUNCTION__, "failed to add socket to SSL object"); + } +# endif /* USE_OPENSSL */ +#endif /* USE_GNUTLS */ + dbg("initialized tls socket %i\n", cd->csock); + } +#endif /* WITH_TLS_TRANSP */ + } + + /* for the via line we need our listening port number */ + if (lport==0){ + memset(&(cd->adr), 0, sizeof(struct sockaddr_in)); + slen=sizeof(struct sockaddr_in); + if (symmetric || transport != SIP_UDP_TRANSPORT) + getsockname(cd->csock, (struct sockaddr *) &(cd->adr), &slen); + else + getsockname(cd->usock, (struct sockaddr *) &(cd->adr), &slen); + lport=ntohs(cd->adr.sin_port); + } +} + +void send_message(char* mes, struct sipsak_con_data *cd, + struct sipsak_counter *sc, struct sipsak_sr_time *srt) { + struct timezone tz; + int ret = -1; + + if (cd->dontsend == 0) { + if (verbose > 2) { + printf("\nrequest:\n%s", mes); + } + /* lets fire the request to the server and store when we did */ + if (cd->csock == -1) { + dbg("\nusing un-connected socket for sending\n"); + ret = sendto(cd->usock, mes, strlen(mes), 0, (struct sockaddr *) &(cd->adr), sizeof(struct sockaddr)); + } + else { + dbg("\nusing connected socket for sending\n"); +#ifdef WITH_TLS_TRANSP + if (transport == SIP_TLS_TRANSPORT) { +# ifdef USE_GNUTLS + ret = gnutls_record_send(tls_session, mes, strlen(mes)); +# else /* USE_GNUTLS */ +# ifdef USE_OPENSSL +# endif /* USE_OPENSSL */ +# endif /* USE_GNUTLS */ + } + else { +#endif /* TLS_TRANSP */ + ret = send(cd->csock, mes, strlen(mes), 0); +#ifdef WITH_TLS_TRANSP + } +#endif /* TLS_TRANSP */ + } + (void)gettimeofday(&(srt->sendtime), &tz); + if (ret==-1) { + if (verbose) + printf("\n"); + perror("send failure"); + exit_code(2, __PRETTY_FUNCTION__, "send failure"); + } +#ifdef HAVE_INET_NTOP + if (verbose > 2) { + printf("\nsend to: %s:%s:%i\n", transport_str, target_dot, rport); + } +#endif + sc->send_counter++; + } + else { + cd->dontsend = 0; + } +} + +void check_socket_error(int socket, int size) { + struct pollfd sockerr; + int ret = 0; + + /* lets see if we at least received an icmp error */ + sockerr.fd=socket; + sockerr.events=POLLERR; + ret = poll(&sockerr, 1, 10); + if (ret==1) { + if (sockerr.revents & POLLERR) { + recvfrom(socket, recv, size, 0, NULL, 0); + if (verbose) + printf("\n"); + perror("send failure"); + if (randtrash == 1) { + printf ("last message before send failure:\n%s\n", request); + log_message(request); + } + exit_code(3, __PRETTY_FUNCTION__, "send failure"); + } + } +} + +int check_for_message(char *recv, int size, struct sipsak_con_data *cd, + struct sipsak_sr_time *srt, struct sipsak_counter *count, + struct sipsak_delay *sd) { + fd_set fd; + struct timezone tz; + struct timeval tv; + double senddiff; + int ret = 0; + + if (cd->dontrecv == 0) { + /* set the timeout and wait for a response */ + tv.tv_sec = sd->retryAfter/1000; + tv.tv_usec = (sd->retryAfter % 1000) * 1000; + + FD_ZERO(&fd); + if (cd->usock != -1) + FD_SET(cd->usock, &fd); + if (cd->csock != -1) + FD_SET(cd->csock, &fd); +#ifdef RAW_SUPPORT + if (rawsock != -1) + FD_SET(rawsock, &fd); +#endif + + ret = select(FD_SETSIZE, &fd, NULL, NULL, &tv); + (void)gettimeofday(&(srt->recvtime), &tz); + } + else { + cd->dontrecv = 0; + } + + /* store the time of our first send */ + if (count->send_counter==1) { + memcpy(&(srt->firstsendt), &(srt->sendtime), sizeof(struct timeval)); + } + if (sd->retryAfter == timer_t1) { + memcpy(&(srt->starttime), &(srt->sendtime), sizeof(struct timeval)); + } + if (ret == 0) + { + /* lets see if we at least received an icmp error */ + if (cd->csock == -1) + check_socket_error(cd->usock, size); + else + check_socket_error(cd->csock, size); + /* printout that we did not received anything */ + if (verbose > 0) { + if (trace == 1) { + printf("%i: timeout after %i ms\n", namebeg, sd->retryAfter); + } + else if (usrloc == 1||invite == 1||message == 1) { + printf("timeout after %i ms\n", sd->retryAfter); + } + else { + printf("** timeout after %i ms**\n", sd->retryAfter); + } + } + if (randtrash == 1) { + printf("did not get a response on this request:\n%s\n", request); + if (cseq_counter < nameend) { + if (count->randretrys == 2) { + printf("sended the following message three " + "times without getting a response:\n%s\n" + "give up further retransmissions...\n", request); + log_message(request); + exit_code(3, __PRETTY_FUNCTION__, "too many retransmissions, giving up..."); + } + else { + printf("resending it without additional " + "random changes...\n\n"); + (count->randretrys)++; + } + } + } + senddiff = deltaT(&(srt->starttime), &(srt->recvtime)); + if (senddiff > (float)timer_final) { + if (timing == 0) { + if (verbose>0) + printf("*** giving up, no final response after %.3f ms\n", senddiff); + log_message(request); + exit_code(3, __PRETTY_FUNCTION__, "timeout (no final response)"); + } + else { + timing--; + count->run++; + sd->all_delay += senddiff; + sd->big_delay = senddiff; + new_transaction(request, response); + sd->retryAfter = timer_t1; + if (timing == 0) { + printf("%.3f/%.3f/%.3f ms\n", sd->small_delay, sd->all_delay / count->run, sd->big_delay); + log_message(request); + exit_code(3, __PRETTY_FUNCTION__, "timeout (no final response)"); + } + } + } + else { + /* set retry time according to RFC3261 */ + if ((inv_trans) || (sd->retryAfter *2 < timer_t2)) { + sd->retryAfter = sd->retryAfter * 2; + } + else { + sd->retryAfter = timer_t2; + } + } + (count->retrans_s_c)++; + if (srt->delaytime.tv_sec == 0) + memcpy(&(srt->delaytime), &(srt->sendtime), sizeof(struct timeval)); + /* if we did not exit until here lets try another send */ + return -1; + } + else if ( ret == -1 ) { + perror("select error"); + exit_code(2, __PRETTY_FUNCTION__, "internal select error"); + } + else if (((cd->usock != -1) && FD_ISSET(cd->usock, &fd)) || ((cd->csock != -1) && FD_ISSET(cd->csock, &fd))) { + if ((cd->usock != -1) && FD_ISSET(cd->usock, &fd)) + ret = cd->usock; + else if ((cd->csock != -1) && FD_ISSET(cd->csock, &fd)) + ret = cd->csock; + else { + printf("unable to determine the socket which received something\n"); + exit_code(2, __PRETTY_FUNCTION__, "failed to determine receiving socket"); + } + /* no timeout, no error ... something has happened :-) */ + if (trace == 0 && usrloc ==0 && invite == 0 && message == 0 && randtrash == 0 && (verbose > 1)) + printf ("\nmessage received"); + } +#ifdef RAW_SUPPORT + else if ((rawsock != -1) && FD_ISSET(rawsock, &fd)) { + if (verbose > 1) + printf("\nreceived ICMP message"); + ret = rawsock; + } +#endif + else { + printf("\nselect returned successfully, nothing received\n"); + return -1; + } + return ret; +} + +int complete_mes(char *mes, int size) { + int cl = 0, headers = 0, len = 0; + char *tmp = NULL; + + cl = get_cl(mes); + dbg("CL: %i\n", cl); + if (cl < 0){ + if (verbose > 0) + printf("missing CL header; waiting for more bytes...\n"); + return 0; + } + tmp = get_body(mes); + dbg("body: '%s'\n", tmp); + headers = tmp - mes; + dbg("length: %i, headers: %i\n", size, headers); + len = headers + cl; + if (len == size) { + if (verbose > 0) + printf("message is complete\n"); + return 1; + } + else if (len > size) { + if (verbose > 0) + printf("waiting for more bytes...\n"); + return 0; + } + else { + /* we received more then the sender claims to sent + * for now we treat this as a complete message + * FIXME: should we store the extra bytes in a buffer and + * truncate the message at the calculated length !? */ + if (verbose > 0) + printf("received too much bytes...\n"); + return 1; + } +} + +int recv_message(char *buf, int size, int inv_trans, + struct sipsak_delay *sd, struct sipsak_sr_time *srt, + struct sipsak_counter *count, struct sipsak_con_data *cd, + struct sipsak_regexp *reg) { + int ret = 0; + int sock = 0; + double tmp_delay; +#ifdef HAVE_INET_NTOP + struct sockaddr_in peer_adr; + socklen_t psize = sizeof(peer_adr); +#endif +#ifdef RAW_SUPPORT + struct sockaddr_in faddr; + struct ip *r_ip_hdr, *s_ip_hdr; + struct icmp *icmp_hdr; + struct udphdr *udp_hdr; + size_t r_ip_len, s_ip_len, icmp_len; + int srcport, dstport; + unsigned int flen; +#endif + + if (cd->buf_tmp) { + buf = cd->buf_tmp; + size = size - cd->buf_tmp_size; + } + sock = check_for_message(buf, size, cd, srt, count, sd); + if (sock <= 1) { + return -1; + } +#ifdef RAW_SUPPORT + if (sock != rawsock) { +#else + else { +#endif + check_socket_error(sock, size); +#ifdef WITH_TLS_TRANSP + if (transport == SIP_TLS_TRANSPORT) { +# ifdef USE_GNUTLS + ret = gnutls_record_recv(tls_session, buf, size); +# else /* USE_GNUTLS */ +# ifdef USE_OPENSSL +# endif /* USE_OPENSSL */ +# endif /* USE_GNUTLS */ + } + else { +#endif /* TLS_TRANSP */ + ret = recvfrom(sock, buf, size, 0, NULL, 0); +#ifdef WITH_TLS_TRANSP + } +#endif /* TLS_TRANSP */ + } +#ifdef RAW_SUPPORT + else { + /* lets check if the ICMP message matches with our + sent packet */ + flen = sizeof(faddr); + memset(&faddr, 0, sizeof(struct sockaddr)); + ret = recvfrom(rawsock, buf, size, 0, (struct sockaddr *)&faddr, &flen); + if (ret == -1) { + perror("error while trying to read from icmp raw socket"); + exit_code(2, __PRETTY_FUNCTION__, "failed to read from ICMP RAW socket"); + } + r_ip_hdr = (struct ip *) buf; + r_ip_len = r_ip_hdr->ip_hl << 2; + + icmp_hdr = (struct icmp *) (buf + r_ip_len); + icmp_len = ret - r_ip_len; + + if (icmp_len < 8) { + if (verbose > 1) + printf(": ignoring (ICMP header length below 8 bytes)\n"); + return -2; + } + else if (icmp_len < 36) { + if (verbose > 1) + printf(": ignoring (ICMP message too short to contain IP and UDP header)\n"); + return -2; + } + s_ip_hdr = (struct ip *) ((char *)icmp_hdr + 8); + s_ip_len = s_ip_hdr->ip_hl << 2; + if (s_ip_hdr->ip_p == IPPROTO_UDP) { + udp_hdr = (struct udphdr *) ((char *)s_ip_hdr + s_ip_len); + srcport = ntohs(udp_hdr->uh_sport); + dstport = ntohs(udp_hdr->uh_dport); + dbg("\nlport: %i, rport: %i\n", lport, rport); + if ((srcport == lport) && (dstport == rport)) { + printf(" (type: %u, code: %u)", icmp_hdr->icmp_type, icmp_hdr->icmp_code); +#ifdef HAVE_INET_NTOP + if (inet_ntop(AF_INET, &faddr.sin_addr, &source_dot[0], INET_ADDRSTRLEN) != NULL) + printf(": from %s\n", source_dot); + else + printf("\n"); +#else + printf("\n"); +#endif // HAVE_INET_NTOP + log_message(request); + exit_code(3, __PRETTY_FUNCTION__, "received ICMP error"); + } + else { + if (verbose > 2) + printf(": ignoring (ICMP message does not match used ports)\n"); + return -2; + } + } + else { + if (verbose > 1) + printf(": ignoring (ICMP data is not a UDP packet)\n"); + return -2; + } + } +#endif // RAW_SUPPORT + if (ret > 0) { + *(buf+ ret) = '\0'; + if (transport != SIP_UDP_TRANSPORT) { + if (verbose > 0) + printf("\nchecking message for completeness...\n"); + if (complete_mes(buf, ret) == 1) { + cd->buf_tmp = NULL; + ret += cd->buf_tmp_size; + cd->buf_tmp_size = 0; + } + else { + if (cd->buf_tmp) { + cd->buf_tmp += ret; + cd->buf_tmp_size += ret; + } + else { + cd->buf_tmp = buf + ret; + cd->buf_tmp_size = ret; + } + cd->dontsend = 1; + ret = -1; + } + } + /* store the biggest delay if one occurred */ + if (srt->delaytime.tv_sec != 0) { + tmp_delay = deltaT(&(srt->delaytime), &(srt->recvtime)); + if (tmp_delay > sd->big_delay) + sd->big_delay = tmp_delay; + if ((sd->small_delay == 0) || (tmp_delay < sd->small_delay)) + sd->small_delay = tmp_delay; + srt->delaytime.tv_sec = 0; + srt->delaytime.tv_usec = 0; + } + if (timing > 0) { + tmp_delay = deltaT(&(srt->sendtime), &(srt->recvtime)); + if (tmp_delay > sd->big_delay) + sd->big_delay = tmp_delay; + if ((sd->small_delay == 0) || (tmp_delay < sd->small_delay)) + sd->small_delay = tmp_delay; + sd->all_delay += tmp_delay; + } +#ifdef HAVE_INET_NTOP + if ((verbose > 2) && (getpeername(sock, (struct sockaddr *)&peer_adr, &psize) == 0) && (inet_ntop(peer_adr.sin_family, &peer_adr.sin_addr, &source_dot[0], INET_ADDRSTRLEN) != NULL)) { + printf("\nreceived from: %s:%s:%i\n", transport_str, + source_dot, ntohs(peer_adr.sin_port)); + } + else if (verbose > 1 && trace == 0 && usrloc == 0) + printf(":\n"); +#else + if (trace == 0 && usrloc == 0) + printf(":\n"); +#endif // HAVE_INET_NTOP + if (!inv_trans && ret > 0 && (regexec(&(reg->proexp), buf, 0, 0, 0) != REG_NOERROR)) { + sd->retryAfter = timer_t1; + } + } + else { + check_socket_error(sock, size); + printf("\nnothing received, select returned error\n"); + exit_code(2, __PRETTY_FUNCTION__, "nothing received, select returned error"); + } + return ret; +} + +/* clears the given sockaddr, fills it with the given data and if a + * socket is given connects the socket to the new target */ +int set_target(struct sockaddr_in *adr, unsigned long target, int port, int socket, int connected) { +#ifdef WITH_TLS_TRANSP + int ret; +# ifdef USE_OPENSSL + int err; + X509* cert; +# endif /* USE_OPENSSL */ +#endif /* WITH_TLS_TRANSP */ + + if (socket != -1 && transport != SIP_UDP_TRANSPORT && connected) { + if (shutdown(socket, SHUT_RDWR) != 0) { + perror("error while shutting down socket"); + } + } + + memset(adr, 0, sizeof(struct sockaddr_in)); + adr->sin_addr.s_addr = target; + adr->sin_port = htons((short)port); + adr->sin_family = AF_INET; + +#ifdef HAVE_INET_NTOP + inet_ntop(adr->sin_family, &adr->sin_addr, &target_dot[0], INET_ADDRSTRLEN); +#endif + + if (socket != -1) { + if (connect(socket, (struct sockaddr *)adr, sizeof(struct sockaddr_in)) == -1) { + perror("connecting socket failed"); + exit_code(2, __PRETTY_FUNCTION__, "connecting socket failed"); + } +#ifdef WITH_TLS_TRANSP + if (transport == SIP_TLS_TRANSPORT) { +# ifdef USE_GNUTLS +# ifdef HAVE_GNUTLS_319 + gnutls_handshake_set_timeout(tls_session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); +# endif + ret = gnutls_handshake(tls_session); + if (ret < 0) { + dbg("TLS Handshake FAILED!!!\n"); + gnutls_perror(ret); + exit_code(3, __PRETTY_FUNCTION__, "TLS handshake failed"); + } + else if (verbose > 2) { + dbg(" TLS Handshake was completed!\n"); + gnutls_session_info(tls_session); + if (verify_certificate_simple(tls_session, domainname) != 0) { + if (ignore_ca_fail == 1) { + if (verbose) { + printf("WARN: Ignoring verification failures of the server certificate\n"); + } + } else { + if (verbose > 1) { + printf("TLS server certificate verification can be ignored with option --tls-ignore-cert-failure.\n"); + } + exit_code(3, __PRETTY_FUNCTION__, "failure during TLS server certificate verification"); + } + } + //verify_certificate_chain(tls_session, domainname, cert_chain, cert_chain_length); + } +# else /* USE_GNUTLS */ +# ifdef USE_OPENSSL + ret = SSL_connect(ssl); + if (ret == 1) { + dbg("TLS connect successful\n"); + if (verbose > 2) { + printf("TLS connect: new connection using %s %s %d\n", + SSL_get_cipher_version(ssl), SSL_get_cipher_name(ssl), + SSL_get_cipher_bits(ssl, 0)); + } + cert = SSL_get_peer_certificate(ssl); + if (cert != 0) { + tls_dump_cert_info("TLS connect: server certificate", cert); + if (SSL_get_verify_result(ssl) != X509_V_OK) { + perror("TLS connect: server certifcate verification failed!!!\n"); + exit_code(3, __PRETTY_FUNCTION__, "TLS server certificate verification falied"); + } + X509_free(cert); + } + else { + perror("TLS connect: server did not present a certificate\n"); + exit_code(3, __PRETTY_FUNCTION__, "missing TLS server certificate"); + } + } + else { + err = SSL_get_error(ssl, ret); + switch (err) { + case SSL_ERROR_ZERO_RETURN: + perror("TLS handshakre failed cleanly'n"); + break; + case SSL_ERROR_WANT_READ: + perror("Need to get more data to finish TLS connect\n"); + break; + case SSL_ERROR_WANT_WRITE: + perror("Need to send more data to finish TLS connect\n"); + break; +#if OPENSSL_VERSION_NUMBER >= 0x00907000L /* 0.9.7 */ + case SSL_ERROR_WANT_CONNECT: + perror("Need to retry connect\n"); + break; + case SSL_ERROR_WANT_ACCEPT: + perror("Need to retry accept'n"); + break; +#endif /* 0.9.7 */ + case SSL_ERROR_WANT_X509_LOOKUP: + perror("Application callback asked to be called again\n"); + break; + case SSL_ERROR_SYSCALL: + printf("TLS connect: %d\n", err); + if (!err) { + if (ret == 0) { + perror("Unexpected EOF occurred while performing TLS connect\n"); + } + else { + printf("IO error: (%d) %s\n", errno, strerror(errno)); + } + } + break; + default: + printf("TLS error: %d\n", err); + } + exit_code(2, __PRETTY_FUNCTION__, "generic SSL error"); + } +# endif /* USE_OPENSSL */ +# endif /* USE_GNUTLS */ + } +#endif /* WITH_TLS_TRANSP */ + } + return 1; +} diff -Nru sipsak-0.9.6+git20170713/src/transport.h sipsak-0.9.7/src/transport.h --- sipsak-0.9.6+git20170713/src/transport.h 1970-01-01 00:00:00.000000000 +0000 +++ sipsak-0.9.7/src/transport.h 2019-04-27 04:54:34.000000000 +0000 @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2005 Nils Ohlmeier + * + * This file belongs to sipsak, a free sip testing tool. + * + * sipsak is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * sipsak is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef SIPSAK_TRANSPORT_H +#define SIPSAK_TRANSPORT_H + +#include "sipsak.h" +#include "shoot.h" + +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else +# ifdef HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif /* TIME_WITH_SYS_TIME */ +#ifdef HAVE_SYS_SOCKET_H +# include +#endif + +struct sipsak_sr_time { + struct timeval sendtime; + struct timeval recvtime; + struct timeval firstsendt; + struct timeval starttime; + struct timeval delaytime; +}; + +struct sipsak_con_data { + struct sockaddr_in adr; + int csock; + int usock; + int dontsend; + int dontrecv; + int connected; + char *buf_tmp; + int buf_tmp_size; +}; + +struct sipsak_counter { + int send_counter; + int retrans_r_c; + int retrans_s_c; + int randretrys; + int run; +}; + +struct sipsak_delay { + int retryAfter; + double big_delay; + double small_delay; + double all_delay; +}; + +void create_sockets(struct sipsak_con_data *cd); + +void close_sockets(struct sipsak_con_data *cd); + +void send_message(char* mes, struct sipsak_con_data *cd, + struct sipsak_counter *sc, struct sipsak_sr_time *srt); + +void check_socket_error(int socket, int size); + +int check_for_message(char *recv, int size, struct sipsak_con_data *cd, + struct sipsak_sr_time *srt, struct sipsak_counter *count, + struct sipsak_delay *sd); + +int recv_message(char *buf, int size, int inv_trans, + struct sipsak_delay *sd, struct sipsak_sr_time *srt, + struct sipsak_counter *count, struct sipsak_con_data *cd, + struct sipsak_regexp *reg); + +int set_target(struct sockaddr_in *adr, unsigned long target, int port, int socket, int connected); +#endif diff -Nru sipsak-0.9.6+git20170713/tests/check_helper.c sipsak-0.9.7/tests/check_helper.c --- sipsak-0.9.6+git20170713/tests/check_helper.c 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/tests/check_helper.c 2019-04-27 04:54:34.000000000 +0000 @@ -5,7 +5,7 @@ #ifdef HAVE_CHECK_H #include -#include "../helper.h" +#include "../src/helper.h" #define RUNNING_CHECK 1 diff -Nru sipsak-0.9.6+git20170713/tests/check_md5.c sipsak-0.9.7/tests/check_md5.c --- sipsak-0.9.6+git20170713/tests/check_md5.c 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/tests/check_md5.c 2019-04-27 04:54:34.000000000 +0000 @@ -5,7 +5,7 @@ #ifdef HAVE_CHECK_H #include -#include "../md5.h" +#include "../src/md5.h" #define RUNNING_CHECK 1 diff -Nru sipsak-0.9.6+git20170713/tests/Makefile.am sipsak-0.9.7/tests/Makefile.am --- sipsak-0.9.6+git20170713/tests/Makefile.am 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/tests/Makefile.am 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -TESTS = check_helper check_md5 - -check_PROGRAMS = check_helper check_md5 - -check_helper_SOURCES = check_helper.c ../helper.h ../helper.c ../exit_code.h ../exit_code.c -check_helper_CFLAGS = @CHECK_CFLAGS@ -DRUNNING_CHECK -check_helper_LDADD = @CHECK_LIBS@ - -check_md5_SOURCES = check_md5.c ../md5.h ../md5.c -check_md5_CFLAGS = @CHECK_CFLAGS@ -DRUNNING_CHECK -check_md5_LDADD = @CHECK_LIBS@ diff -Nru sipsak-0.9.6+git20170713/transport.c sipsak-0.9.7/transport.c --- sipsak-0.9.6+git20170713/transport.c 2017-07-13 14:47:05.000000000 +0000 +++ sipsak-0.9.7/transport.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1251 +0,0 @@ -/* - * Copyright (C) 2005 Nils Ohlmeier - * - * This file belongs to sipsak, a free sip testing tool. - * - * sipsak is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * sipsak is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#include "sipsak.h" - -#ifdef TIME_WITH_SYS_TIME -# include -# include -#else -# ifdef HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif /* TIME_WITH_SYS_TIME */ -#ifdef HAVE_UNISTD_H -# ifdef HAVE_SYS_TYPES_H -# include -# endif -# include -#endif -#ifdef HAVE_SYS_SOCKET_H -# include -#endif -#ifdef HAVE_SYS_POLL_H -# include -#endif -#ifdef HAVE_ARPA_INET_H -# include -#endif - -#include "transport.h" -#include "shoot.h" - -#ifdef RAW_SUPPORT -# ifdef HAVE_NETINET_IN_SYSTM_H -# include -# endif -# ifdef HAVE_NETINET_IP_H -# include -# endif -# ifdef HAVE_NETINET_IP_ICMP_H -# include -# endif -# ifdef HAVE_NETINET_UDP_H -# define __FAVOR_BSD -# include -# endif -#endif /* RAW_SUPPORT */ - -#ifdef WITH_TLS_TRANSP -# ifdef USE_GNUTLS -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# else -# ifdef USE_OPENSSL -# define _BSD_SOURCE 1 -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# endif -# endif -#endif /* WITH_TLS_TRANSP */ - -#include "exit_code.h" -#include "helper.h" -#include "header_f.h" - -#ifdef RAW_SUPPORT -int rawsock; -#endif - -#ifdef WITH_TLS_TRANSP -# ifdef USE_GNUTLS -void check_alert(gnutls_session_t session, int ret) { - int last_alert; - - if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED || - ret == GNUTLS_E_FATAL_ALERT_RECEIVED) { - last_alert = gnutls_alert_get(session); - printf("Received TLS alert: '%d': %s\n", last_alert, - gnutls_alert_get_name(last_alert)); - } -} - -/* all the available CRLs */ -gnutls_x509_crl_t *crl_list; -int crl_list_size; - -/* all the available trusted CAs */ -gnutls_x509_crt_t *ca_list; -int ca_list_size; - -/* verifies a certificate against an other certificate which is supposed to - * be it's issuer. Also checks the crl_list of the certificate is revoked. - */ -static void verify_cert2(gnutls_x509_crt_t crt, gnutls_x509_crt_t issuer, - gnutls_x509_crl_t *crl_list, int crl_list_size) { - unsigned int output; - time_t now = time(0); - size_t name_size; - char name[64]; - - /* print information about the certificates to be checked */ - name_size = sizeof(name); - gnutls_x509_crt_get_dn(crt, name, &name_size); - - printf("Certificate: %s\n", name); - - name_size = sizeof(name); - gnutls_x509_crt_get_issuer_dn(crt, name, &name_size); - - printf("Issued by: %s\n", name); - - /* Get the DN of the issuer cert. */ - name_size = sizeof(name); - gnutls_x509_crt_get_dn(issuer, name, &name_size); - - printf("Checking against: %s\n", name); - - /* Do the actual verification */ - gnutls_x509_crt_verify(crt, &issuer, 1, 0, &output); - - if (output & GNUTLS_CERT_INVALID) { - printf("Certificate not trusted!!!"); - if (output & GNUTLS_CERT_SIGNER_NOT_FOUND) { - printf(": no issuer was found\n"); - } - if (output & GNUTLS_CERT_SIGNER_NOT_CA) { - printf(": issuer is not a CA\n"); - } - } - else { - printf("Certificate trusted'n"); - } - - /* Now check the expiration dates */ - if (gnutls_x509_crt_get_activation_time(crt) > now) { - printf("Certificate not yet activated!\n"); - } - if (gnutls_x509_crt_get_expiration_time(crt) < now) { - printf("Certificate expired!\n"); - } - /* Check if the certificate is revoked */ - if (gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size) == 1) { - printf("Certificate is revoked!\n"); - } -} - -/* Verifies a certificate against our trusted CA list. Also checks the crl_list - * if the certificate is revoked - */ -static void verify_last_cert(gnutls_x509_crt_t crt, gnutls_x509_crt_t *ca_list, - int ca_list_size, gnutls_x509_crl_t *crl_list, int crl_list_size) { - unsigned int output; - time_t now = time(0); - size_t name_size; - char name[64]; - - /* Print information about the certificates to be checked */ - name_size = sizeof(name); - gnutls_x509_crt_get_dn(crt, name, &name_size); - printf("Certificate: %s\n", name); - - name_size = sizeof(name); - gnutls_x509_crt_get_issuer_dn(crt, name, &name_size); - printf("Issued by: %s\n", name); - - /* Do the actual verification */ - gnutls_x509_crt_verify(crt, ca_list, ca_list_size, - GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT, &output); - if (output & GNUTLS_CERT_INVALID) { - printf("Certificate not truested!\n"); - if (output & GNUTLS_CERT_SIGNER_NOT_CA) { - printf(": Issuer is not a CA\n"); - } - } - else { - printf("Certificate trusted\n"); - } - - /* Now check the expiration dates */ - if (gnutls_x509_crt_get_activation_time(crt) > now) { - printf("Certificate now yet activated!\n"); - } - if (gnutls_x509_crt_get_expiration_time(crt) < now) { - printf("Certificate expired!\n"); - } - /* Check of the vertificate is revoked */ - if (gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size) == 1) { - printf("Certificate is revoked!\n"); - } -} - -/* this function will try yo verify the peer's certificate chain, ans - * also check if the hostname matches, and the activation and expiration dates. - */ -void verify_certificate_chain(gnutls_session_t session, const char *hostname, - const gnutls_datum_t *cert_chain, int cert_chain_length) { - int i; - gnutls_x509_crt_t *cert; - - cert = malloc(sizeof(*cert) * cert_chain_length); - if (!cert) { - printf("gnutla: failed to allocate memory for cert chain verification'n"); - return; - } - - /* import all the certificates in the chain to native certificate format */ - for (i = 0; i < cert_chain_length; i++) { - gnutls_x509_crt_init(&cert[i]); - gnutls_x509_crt_import(cert[i], &cert_chain[i], GNUTLS_X509_FMT_DER); - } - - /* if the last certificate in the chain is seld signed ignore it. - * that is because we want to check against our trusted certificate list - */ - if (gnutls_x509_crt_check_issuer(cert[cert_chain_length - 1], - cert[cert_chain_length -1]) > 0 && cert_chain_length > 0) { - cert_chain_length--; - } - /* now verify the certificates against other issuers in the chain */ - for (i = 1; i < cert_chain_length; i++) { - verify_cert2(cert[i - 1], cert[i], crl_list, crl_list_size); - } - /* here we must verify the last certificate in the chain against our - * trusted CA list - */ - verify_last_cert(cert[cert_chain_length - 1], ca_list, ca_list_size, - crl_list, crl_list_size); - /* check if the name in the first certificate matches our destination */ - if (!gnutls_x509_crt_check_hostname(cert[0], hostname)) { - printf("The certificate's owner does not match hostname '%s'\n", - hostname); - } - - for (i = 0; i < cert_chain_length; i++) { - gnutls_x509_crt_deinit(cert[i]); - } - return; -} - -int verify_certificate_simple(gnutls_session_t session, const char *hostname) { - unsigned int status, cert_list_size; - const gnutls_datum_t *cert_list; - int ret; - gnutls_x509_crt_t cert; - - // this verification function usese the trusted CAs in the credentials - // structure. so you must have installed on or more CA certificates. - ret = gnutls_certificate_verify_peers2(session, &status); - - if (ret < 0) { - printf("gnutls verify peer failed.\n"); - return -1; - } - ret = 0; - - if (status & GNUTLS_CERT_INVALID) { - ret |= -2; - printf("The certificate is not trustworthy\n"); - if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) { - printf("The certificate hasn't got a known issuer.\n"); - ret |= -4; - } - if (status & GNUTLS_CERT_SIGNER_NOT_CA) { - printf("The certificate issuer is not a CA\n"); - ret |= -8; - } - } - if (status & GNUTLS_CERT_REVOKED) { - printf("The certificate has beend revoked.\n"); - ret = -16; - } - if (ret != 0 && ignore_ca_fail == 0) { - return ret; - } - - // from here on it works only with X509 certs - if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509){ - printf("The server certificate is not X509.\n"); - return -32;; - } - if (gnutls_x509_crt_init(&cert) < 0) { - printf("gnutls crt init failed.\n"); - return -64; - } - - cert_list = gnutls_certificate_get_peers(session, &cert_list_size); - if (cert_list == NULL) { - printf("gnutls did not found a server certificate.\n"); - return -128; - } - - // this not a real world check as only the first cert is checked! - if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER)) { - printf("gnutls failed to parse server certificate.\n"); - return -256; - } - - // beware here we do not check for errors - if (gnutls_x509_crt_get_expiration_time(cert) < time(0)) { - printf("The server certificate is expired.\n"); - return -512; - } - if (gnutls_x509_crt_get_activation_time(cert) > time(0)) { - printf("The server certificate is not yet activated.\n"); - return -1024; - } - if (!gnutls_x509_crt_check_hostname(cert, hostname)) { - printf("The server certificate's owner does not match hostname '%s'\n", - hostname); - return -2048; - } - - gnutls_x509_crt_deinit(cert); - - return ret; -} - -static const char *bin2hex(const void *bin, size_t bin_size) { - static char printable[110]; - const unsigned char *_bin = bin; - char *print; - size_t i; - - if (bin_size > 50) { - bin_size = 50; - } - - print = printable; - for (i=0; i < bin_size; i++) { - sprintf(print, "%.2x ", _bin[i]); - print += 2; - } - - return printable; -} - -void print_x509_certificate_info(gnutls_session_t session) { - char serial[40]; - char dn[128]; - size_t size; - unsigned int algo, bits; - time_t expiration_time, activation_time; - const gnutls_datum_t *cert_list; - unsigned int cert_list_size = 0; - gnutls_x509_crt_t cert; - - // check if we got a X.509 cert - if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) { - printf("TLS session did not received a X.509 certificate\n"); - return; - } - - cert_list = gnutls_certificate_get_peers(session, &cert_list_size); - printf("Peer provided %u certificate(s)\n", cert_list_size); - - if (cert_list_size > 0) { - // print only informations about the first cert - gnutls_x509_crt_init(&cert); - gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER); - printf("Certificate info:\n"); - activation_time = gnutls_x509_crt_get_activation_time(cert); - printf("\tCertificate is valid since: %s", ctime(&activation_time)); - expiration_time = gnutls_x509_crt_get_expiration_time(cert); - printf("\tCertificate expires: %s", ctime(&expiration_time)); - // print the serial number of the certificate - size = sizeof(serial); - gnutls_x509_crt_get_serial(cert, serial, &size); - printf("\tCertificate serail number: %s\n", bin2hex(serial, size)); - // extract public key algorithm - algo = gnutls_x509_crt_get_pk_algorithm(cert, &bits); - printf("\tCertificate public key algorithm: %s\n", gnutls_pk_algorithm_get_name(algo)); - // print version of x509 cert - printf("\tCertificate version: #%d\n", gnutls_x509_crt_get_version(cert)); - // print name of the certificate - size = sizeof(dn); - gnutls_x509_crt_get_dn(cert, dn, &size); - printf("\tDN: %s\n", dn); - // print subject alt name of the certificate - size = sizeof(dn); - if (gnutls_x509_crt_get_subject_alt_name(cert, 0, dn, &size, NULL) == 0) { - printf("\tSubject Alt Name: %s\n", dn); - } - // print the algorithm which was used for signing the cert - algo = gnutls_x509_crt_get_signature_algorithm(cert); - printf("\tCA's signature algorithm: %s\n", gnutls_pk_algorithm_get_name(algo)); - // print the name of the CA - size = sizeof(dn); - if (gnutls_x509_crt_get_issuer_dn(cert, dn, &size) == 0) { - printf("\tCA's DN: %s\n", dn); - } - // print the CA status flags if present - if (gnutls_x509_crt_get_ca_status(cert, &algo) > 0 && algo != 0) { - printf("\tCA status flag is set\n"); - } - // print the fingerprint of the cert - size = sizeof(dn); - // FIXME - if (gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, dn, &size) == 0) { - printf("\tFingerprint of the certificate: %s\n", dn); - } - - - gnutls_x509_crt_deinit(cert); - } -} - -void gnutls_session_info(gnutls_session_t session) { - const char *tmp; - gnutls_credentials_type_t cred; - gnutls_kx_algorithm_t kx; - - // print the key exchange algorithm name - kx = gnutls_kx_get(session); - tmp = gnutls_kx_get_name(kx); - printf("Key Echange: %s\n", tmp); - - // check the authentication type - cred = gnutls_auth_get_type(session); - switch(cred) { - case GNUTLS_CRD_SRP: - printf("SRP session with username %s\n", - gnutls_srp_server_get_username(session)); - break; - case GNUTLS_CRD_ANON: - printf("Anonymous DH using prime of %d bits\n", - gnutls_dh_get_prime_bits(session)); - break; - case GNUTLS_CRD_CERTIFICATE: - // check if we have been using ephemeral DH - if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS) { - printf("Emphemeral DH using prime of %d bits\n", - gnutls_dh_get_prime_bits(session)); - } - // print certificate informations if available - print_x509_certificate_info(session); - break; - default: - printf("UNKNOWN GNUTLS authentication type!!!\n"); - } - - // print protocols name - tmp = gnutls_protocol_get_name(gnutls_protocol_get_version(session)); - printf("Protocol: %s\n", tmp); - - // print certificate type - tmp = gnutls_certificate_type_get_name(gnutls_certificate_type_get(session)); - printf("Certificate Type: %s\n", tmp); - - // print the compression algorithm - tmp = gnutls_compression_get_name(gnutls_compression_get(session)); - printf("Compression: %s\n", tmp); - - // print name of the cipher - tmp = gnutls_cipher_get_name(gnutls_cipher_get(session)); - printf("Cipher: %s\n", tmp); - - // print the MAC algorithm - tmp = gnutls_mac_get_name(gnutls_mac_get(session)); - printf("MAC: %s\n", tmp); -} -# else -# ifdef USE_OPENSSL -void set_tls_options() { -#if OPENSSL_VERSION_NUMBER >= 0x0009070000 /* 0.9.7 */ - SSL_CTX_set_options(ctx, SSL_OP_ALL | - SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | - SSL_OP_CIPHER_SERVER_PREFERENCE); -#else - SSL_CTX_set_options(ctx, SSL_OP_ALL); -#endif -} - -void create_tls_ctx() { - SSL_METHOD *method = NULL; - - method = TLSv1_method(); - ctx = SSL_CTX_new(method); - if (ctx == NULL) { - ERR_print_errors_fp(stderr); - perror("create_tls_ctx: failed to create TLS ctx"); - exit_code(2, __PRETTY_FUNCTION__, "failed to create TLS ctx"); - } - /*if (!SSL_CTX_use_certificate_chain_file(ctx, cert_file)) { - perror("create_tls_ctx: failed to load certificate file"); - exit_code(2); - } - if (SSL_CTX_load_verify_locations(ctx, ca_file, 0) != 1) { - perror("create_tls_ctx: failed to load CA cert"); - exit_code(2); - } - SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(ca_file)); - if (SSL_CTX_get_client_CA_list(ctx) == 0) { - perror("create_tls_ctx: failed to set client CA list"); - exit_code(2); - }*/ - SSL_CTX_set_cipher_list(ctx, 0); - SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0); - SSL_CTX_set_verify_depth(ctx, 5); - set_tls_options(); - SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); - SSL_CTX_set_session_id_context(ctx, 0, 0); -} - -void tls_dump_cert_info(char* s, X509* cert) { - char *subj, *issuer; - - subj = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); - issuer = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); - - printf("%s subject: '%s'\n", s ? s: "", subj); - printf("%s issuer: '%s'\n", s ? s : "", issuer); - OPENSSL_free(subj); - OPENSSL_free(issuer); -} -# endif /* USE_OPENSSL */ -# endif /* USE_GNUTLS */ -#endif /* WITH_TLS_TRANSP */ - -void create_sockets(struct sipsak_con_data *cd) { - socklen_t slen; - - memset(&(cd->adr), 0, sizeof(struct sockaddr_in)); - cd->adr.sin_family = AF_INET; - if(local_ip) { - cd->adr.sin_addr.s_addr = inet_addr(local_ip); - } else { - cd->adr.sin_addr.s_addr = htonl( INADDR_ANY); - } - cd->adr.sin_port = htons((short)lport); - - if (transport == SIP_UDP_TRANSPORT) { - /* create the un-connected socket */ - if (!symmetric) { - cd->usock = (int)socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (cd->usock==-1) { - perror("unconnected UDP socket creation failed"); - exit_code(2, __PRETTY_FUNCTION__, "failed to create unconnected UDP socket"); - } - if (bind(cd->usock, (struct sockaddr *) &(cd->adr), sizeof(struct sockaddr_in) )==-1) { - perror("unconnected UDP socket binding failed"); - exit_code(2, __PRETTY_FUNCTION__, "failed to bind unconnected UDP socket"); - } - } - - -#ifdef RAW_SUPPORT - /* try to create the raw socket */ - rawsock = (int)socket(PF_INET, SOCK_RAW, IPPROTO_ICMP); - if (rawsock==-1) { - if (verbose>1) - fprintf(stderr, "warning: need raw socket (root privileges) to receive all ICMP errors\n"); -#endif - /* create the connected socket as a primitve alternative to the - raw socket*/ - cd->csock = (int)socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (cd->csock==-1) { - perror("connected UDP socket creation failed"); - exit_code(2, __PRETTY_FUNCTION__, "failed to create connected UDP socket"); - } - - if (!symmetric) - cd->adr.sin_port = htons((short)0); - if (bind(cd->csock, (struct sockaddr *) &(cd->adr), sizeof(struct sockaddr_in) )==-1) { - perror("connected UDP socket binding failed"); - exit_code(2, __PRETTY_FUNCTION__, "failed to bind connected UDP socket"); - } -#ifdef RAW_SUPPORT - } - else if (symmetric) { - cd->csock = (int)socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (cd->csock==-1) { - perror("connected UDP socket creation failed"); - exit_code(2, __PRETTY_FUNCTION__, "failed to create connected UDP socket"); - } - if (bind(cd->csock, (struct sockaddr *) &(cd->adr), sizeof(struct sockaddr_in) )==-1) { - perror("connected UDP socket binding failed"); - exit_code(2, __PRETTY_FUNCTION__, "failed to bind connected UDP socket"); - } - } -#endif - } - else { - cd->csock = (int)socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); - if (cd->csock==-1) { - perror("TCP socket creation failed"); - exit_code(2, __PRETTY_FUNCTION__, "failed to create TCP socket"); - } - if (bind(cd->csock, (struct sockaddr *) &(cd->adr), sizeof(struct sockaddr_in) )==-1) { - perror("TCP socket binding failed"); - exit_code(2, __PRETTY_FUNCTION__, "failed to bind TCP socket"); - } -#ifdef WITH_TLS_TRANSP - if (transport == SIP_TLS_TRANSPORT) { -#ifdef USE_GNUTLS - // initialixe the TLS session - gnutls_init(&tls_session, GNUTLS_CLIENT); - // use default priorities - gnutls_set_default_priority(tls_session); - // put the X509 credentials to the session - gnutls_credentials_set(tls_session, GNUTLS_CRD_CERTIFICATE, xcred); - // add the FD to the session -# ifdef HAVE_GNUTLS_319 - gnutls_transport_set_int(tls_session, cd->csock); -# else - gnutls_transport_set_ptr(tls_session, (gnutls_transport_ptr_t)(intptr_t)cd->csock); -# endif -#else /* USE_GNUTLS */ -# ifdef USE_OPENSSL - create_tls_ctx(); - ssl = SSL_new(ctx); - if (ssl == NULL) { - perror("TLS failed to create SSL object"); - exit_code(2, __PRETTY_FUNCTION__, "failed to create SSL object"); - } - if (SSL_set_fd(ssl, cd->csock) != 1) { - perror("TLS failed to add socket to SSL object"); - exit_code(2, __PRETTY_FUNCTION__, "failed to add socket to SSL object"); - } -# endif /* USE_OPENSSL */ -#endif /* USE_GNUTLS */ - dbg("initialized tls socket %i\n", cd->csock); - } -#endif /* WITH_TLS_TRANSP */ - } - - /* for the via line we need our listening port number */ - if (lport==0){ - memset(&(cd->adr), 0, sizeof(struct sockaddr_in)); - slen=sizeof(struct sockaddr_in); - if (symmetric || transport != SIP_UDP_TRANSPORT) - getsockname(cd->csock, (struct sockaddr *) &(cd->adr), &slen); - else - getsockname(cd->usock, (struct sockaddr *) &(cd->adr), &slen); - lport=ntohs(cd->adr.sin_port); - } -} - -void close_sockets(struct sipsak_con_data *cd) { - if (transport == SIP_UDP_TRANSPORT) { - } - else { -#ifdef WITH_TLS_TRANSP - if (transport == SIP_TLS_TRANSPORT) { -# ifdef USE_GNUTLS - gnutls_bye(tls_session, GNUTLS_SHUT_RDWR); -# else /* USE_GNUTLS */ -# ifdef USE_OPENSSL -# endif /* USE_OPENSSL */ -# endif /* USE_GNUTLS */ - } -#endif /* WITH_TLS_TRANSP */ - shutdown(cd->csock, SHUT_RDWR); - } - dbg("sockets closed\n"); -} - -void send_message(char* mes, struct sipsak_con_data *cd, - struct sipsak_counter *sc, struct sipsak_sr_time *srt) { - struct timezone tz; - int ret = -1; - - if (cd->dontsend == 0) { - if (verbose > 2) { - printf("\nrequest:\n%s", mes); - } - /* lets fire the request to the server and store when we did */ - if (cd->csock == -1) { - dbg("\nusing un-connected socket for sending\n"); - ret = sendto(cd->usock, mes, strlen(mes), 0, (struct sockaddr *) &(cd->adr), sizeof(struct sockaddr)); - } - else { - dbg("\nusing connected socket for sending\n"); -#ifdef WITH_TLS_TRANSP - if (transport == SIP_TLS_TRANSPORT) { -# ifdef USE_GNUTLS - ret = gnutls_record_send(tls_session, mes, strlen(mes)); -# else /* USE_GNUTLS */ -# ifdef USE_OPENSSL -# endif /* USE_OPENSSL */ -# endif /* USE_GNUTLS */ - } - else { -#endif /* TLS_TRANSP */ - ret = send(cd->csock, mes, strlen(mes), 0); -#ifdef WITH_TLS_TRANSP - } -#endif /* TLS_TRANSP */ - } - (void)gettimeofday(&(srt->sendtime), &tz); - if (ret==-1) { - if (verbose) - printf("\n"); - perror("send failure"); - exit_code(2, __PRETTY_FUNCTION__, "send failure"); - } -#ifdef HAVE_INET_NTOP - if (verbose > 2) { - printf("\nsend to: %s:%s:%i\n", transport_str, target_dot, rport); - } -#endif - sc->send_counter++; - } - else { - cd->dontsend = 0; - } -} - -void check_socket_error(int socket, int size) { - struct pollfd sockerr; - int ret = 0; - - /* lets see if we at least received an icmp error */ - sockerr.fd=socket; - sockerr.events=POLLERR; - ret = poll(&sockerr, 1, 10); - if (ret==1) { - if (sockerr.revents & POLLERR) { - recvfrom(socket, recv, size, 0, NULL, 0); - if (verbose) - printf("\n"); - perror("send failure"); - if (randtrash == 1) { - printf ("last message before send failure:\n%s\n", req); - log_message(req); - } - exit_code(3, __PRETTY_FUNCTION__, "send failure"); - } - } -} - -int check_for_message(char *recv, int size, struct sipsak_con_data *cd, - struct sipsak_sr_time *srt, struct sipsak_counter *count, - struct sipsak_delay *sd) { - fd_set fd; - struct timezone tz; - struct timeval tv; - double senddiff; - int ret = 0; - - if (cd->dontrecv == 0) { - /* set the timeout and wait for a response */ - tv.tv_sec = sd->retryAfter/1000; - tv.tv_usec = (sd->retryAfter % 1000) * 1000; - - FD_ZERO(&fd); - if (cd->usock != -1) - FD_SET(cd->usock, &fd); - if (cd->csock != -1) - FD_SET(cd->csock, &fd); -#ifdef RAW_SUPPORT - if (rawsock != -1) - FD_SET(rawsock, &fd); -#endif - - ret = select(FD_SETSIZE, &fd, NULL, NULL, &tv); - (void)gettimeofday(&(srt->recvtime), &tz); - } - else { - cd->dontrecv = 0; - } - - /* store the time of our first send */ - if (count->send_counter==1) { - memcpy(&(srt->firstsendt), &(srt->sendtime), sizeof(struct timeval)); - } - if (sd->retryAfter == timer_t1) { - memcpy(&(srt->starttime), &(srt->sendtime), sizeof(struct timeval)); - } - if (ret == 0) - { - /* lets see if we at least received an icmp error */ - if (cd->csock == -1) - check_socket_error(cd->usock, size); - else - check_socket_error(cd->csock, size); - /* printout that we did not received anything */ - if (verbose > 0) { - if (trace == 1) { - printf("%i: timeout after %i ms\n", namebeg, sd->retryAfter); - } - else if (usrloc == 1||invite == 1||message == 1) { - printf("timeout after %i ms\n", sd->retryAfter); - } - else { - printf("** timeout after %i ms**\n", sd->retryAfter); - } - } - if (randtrash == 1) { - printf("did not get a response on this request:\n%s\n", req); - if (cseq_counter < nameend) { - if (count->randretrys == 2) { - printf("sended the following message three " - "times without getting a response:\n%s\n" - "give up further retransmissions...\n", req); - log_message(req); - exit_code(3, __PRETTY_FUNCTION__, "too many retransmissions, giving up..."); - } - else { - printf("resending it without additional " - "random changes...\n\n"); - (count->randretrys)++; - } - } - } - senddiff = deltaT(&(srt->starttime), &(srt->recvtime)); - if (senddiff > (float)timer_final) { - if (timing == 0) { - if (verbose>0) - printf("*** giving up, no final response after %.3f ms\n", senddiff); - log_message(req); - exit_code(3, __PRETTY_FUNCTION__, "timeout (no final response)"); - } - else { - timing--; - count->run++; - sd->all_delay += senddiff; - sd->big_delay = senddiff; - new_transaction(req, rep); - sd->retryAfter = timer_t1; - if (timing == 0) { - printf("%.3f/%.3f/%.3f ms\n", sd->small_delay, sd->all_delay / count->run, sd->big_delay); - log_message(req); - exit_code(3, __PRETTY_FUNCTION__, "timeout (no final response)"); - } - } - } - else { - /* set retry time according to RFC3261 */ - if ((inv_trans) || (sd->retryAfter *2 < timer_t2)) { - sd->retryAfter = sd->retryAfter * 2; - } - else { - sd->retryAfter = timer_t2; - } - } - (count->retrans_s_c)++; - if (srt->delaytime.tv_sec == 0) - memcpy(&(srt->delaytime), &(srt->sendtime), sizeof(struct timeval)); - /* if we did not exit until here lets try another send */ - return -1; - } - else if ( ret == -1 ) { - perror("select error"); - exit_code(2, __PRETTY_FUNCTION__, "internal select error"); - } - else if (((cd->usock != -1) && FD_ISSET(cd->usock, &fd)) || ((cd->csock != -1) && FD_ISSET(cd->csock, &fd))) { - if ((cd->usock != -1) && FD_ISSET(cd->usock, &fd)) - ret = cd->usock; - else if ((cd->csock != -1) && FD_ISSET(cd->csock, &fd)) - ret = cd->csock; - else { - printf("unable to determine the socket which received something\n"); - exit_code(2, __PRETTY_FUNCTION__, "failed to determine receiving socket"); - } - /* no timeout, no error ... something has happened :-) */ - if (trace == 0 && usrloc ==0 && invite == 0 && message == 0 && randtrash == 0 && (verbose > 1)) - printf ("\nmessage received"); - } -#ifdef RAW_SUPPORT - else if ((rawsock != -1) && FD_ISSET(rawsock, &fd)) { - if (verbose > 1) - printf("\nreceived ICMP message"); - ret = rawsock; - } -#endif - else { - printf("\nselect returned successfully, nothing received\n"); - return -1; - } - return ret; -} - -int complete_mes(char *mes, int size) { - int cl = 0, headers = 0, len = 0; - char *tmp = NULL; - - cl = get_cl(mes); - dbg("CL: %i\n", cl); - if (cl < 0){ - if (verbose > 0) - printf("missing CL header; waiting for more bytes...\n"); - return 0; - } - tmp = get_body(mes); - dbg("body: '%s'\n", tmp); - headers = tmp - mes; - dbg("length: %i, headers: %i\n", size, headers); - len = headers + cl; - if (len == size) { - if (verbose > 0) - printf("message is complete\n"); - return 1; - } - else if (len > size) { - if (verbose > 0) - printf("waiting for more bytes...\n"); - return 0; - } - else { - /* we received more then the sender claims to sent - * for now we treat this as a complete message - * FIXME: should we store the extra bytes in a buffer and - * truncate the message at the calculated length !? */ - if (verbose > 0) - printf("received too much bytes...\n"); - return 1; - } -} - -int recv_message(char *buf, int size, int inv_trans, - struct sipsak_delay *sd, struct sipsak_sr_time *srt, - struct sipsak_counter *count, struct sipsak_con_data *cd, - struct sipsak_regexp *reg) { - int ret = 0; - int sock = 0; - double tmp_delay; -#ifdef HAVE_INET_NTOP - struct sockaddr_in peer_adr; - socklen_t psize = sizeof(peer_adr); -#endif -#ifdef RAW_SUPPORT - struct sockaddr_in faddr; - struct ip *r_ip_hdr, *s_ip_hdr; - struct icmp *icmp_hdr; - struct udphdr *udp_hdr; - size_t r_ip_len, s_ip_len, icmp_len; - int srcport, dstport; - unsigned int flen; -#endif - - if (cd->buf_tmp) { - buf = cd->buf_tmp; - size = size - cd->buf_tmp_size; - } - sock = check_for_message(buf, size, cd, srt, count, sd); - if (sock <= 1) { - return -1; - } -#ifdef RAW_SUPPORT - if (sock != rawsock) { -#else - else { -#endif - check_socket_error(sock, size); -#ifdef WITH_TLS_TRANSP - if (transport == SIP_TLS_TRANSPORT) { -# ifdef USE_GNUTLS - ret = gnutls_record_recv(tls_session, buf, size); -# else /* USE_GNUTLS */ -# ifdef USE_OPENSSL -# endif /* USE_OPENSSL */ -# endif /* USE_GNUTLS */ - } - else { -#endif /* TLS_TRANSP */ - ret = recvfrom(sock, buf, size, 0, NULL, 0); -#ifdef WITH_TLS_TRANSP - } -#endif /* TLS_TRANSP */ - } -#ifdef RAW_SUPPORT - else { - /* lets check if the ICMP message matches with our - sent packet */ - flen = sizeof(faddr); - memset(&faddr, 0, sizeof(struct sockaddr)); - ret = recvfrom(rawsock, buf, size, 0, (struct sockaddr *)&faddr, &flen); - if (ret == -1) { - perror("error while trying to read from icmp raw socket"); - exit_code(2, __PRETTY_FUNCTION__, "failed to read from ICMP RAW socket"); - } - r_ip_hdr = (struct ip *) buf; - r_ip_len = r_ip_hdr->ip_hl << 2; - - icmp_hdr = (struct icmp *) (buf + r_ip_len); - icmp_len = ret - r_ip_len; - - if (icmp_len < 8) { - if (verbose > 1) - printf(": ignoring (ICMP header length below 8 bytes)\n"); - return -2; - } - else if (icmp_len < 36) { - if (verbose > 1) - printf(": ignoring (ICMP message too short to contain IP and UDP header)\n"); - return -2; - } - s_ip_hdr = (struct ip *) ((char *)icmp_hdr + 8); - s_ip_len = s_ip_hdr->ip_hl << 2; - if (s_ip_hdr->ip_p == IPPROTO_UDP) { - udp_hdr = (struct udphdr *) ((char *)s_ip_hdr + s_ip_len); - srcport = ntohs(udp_hdr->uh_sport); - dstport = ntohs(udp_hdr->uh_dport); - dbg("\nlport: %i, rport: %i\n", lport, rport); - if ((srcport == lport) && (dstport == rport)) { - printf(" (type: %u, code: %u)", icmp_hdr->icmp_type, icmp_hdr->icmp_code); -#ifdef HAVE_INET_NTOP - if (inet_ntop(AF_INET, &faddr.sin_addr, &source_dot[0], INET_ADDRSTRLEN) != NULL) - printf(": from %s\n", source_dot); - else - printf("\n"); -#else - printf("\n"); -#endif // HAVE_INET_NTOP - log_message(req); - exit_code(3, __PRETTY_FUNCTION__, "received ICMP error"); - } - else { - if (verbose > 2) - printf(": ignoring (ICMP message does not match used ports)\n"); - return -2; - } - } - else { - if (verbose > 1) - printf(": ignoring (ICMP data is not a UDP packet)\n"); - return -2; - } - } -#endif // RAW_SUPPORT - if (ret > 0) { - *(buf+ ret) = '\0'; - if (transport != SIP_UDP_TRANSPORT) { - if (verbose > 0) - printf("\nchecking message for completeness...\n"); - if (complete_mes(buf, ret) == 1) { - cd->buf_tmp = NULL; - ret += cd->buf_tmp_size; - cd->buf_tmp_size = 0; - } - else { - if (cd->buf_tmp) { - cd->buf_tmp += ret; - cd->buf_tmp_size += ret; - } - else { - cd->buf_tmp = buf + ret; - cd->buf_tmp_size = ret; - } - cd->dontsend = 1; - ret = -1; - } - } - /* store the biggest delay if one occurred */ - if (srt->delaytime.tv_sec != 0) { - tmp_delay = deltaT(&(srt->delaytime), &(srt->recvtime)); - if (tmp_delay > sd->big_delay) - sd->big_delay = tmp_delay; - if ((sd->small_delay == 0) || (tmp_delay < sd->small_delay)) - sd->small_delay = tmp_delay; - srt->delaytime.tv_sec = 0; - srt->delaytime.tv_usec = 0; - } - if (timing > 0) { - tmp_delay = deltaT(&(srt->sendtime), &(srt->recvtime)); - if (tmp_delay > sd->big_delay) - sd->big_delay = tmp_delay; - if ((sd->small_delay == 0) || (tmp_delay < sd->small_delay)) - sd->small_delay = tmp_delay; - sd->all_delay += tmp_delay; - } -#ifdef HAVE_INET_NTOP - if ((verbose > 2) && (getpeername(sock, (struct sockaddr *)&peer_adr, &psize) == 0) && (inet_ntop(peer_adr.sin_family, &peer_adr.sin_addr, &source_dot[0], INET_ADDRSTRLEN) != NULL)) { - printf("\nreceived from: %s:%s:%i\n", transport_str, - source_dot, ntohs(peer_adr.sin_port)); - } - else if (verbose > 1 && trace == 0 && usrloc == 0) - printf(":\n"); -#else - if (trace == 0 && usrloc == 0) - printf(":\n"); -#endif // HAVE_INET_NTOP - if (!inv_trans && ret > 0 && (regexec(&(reg->proexp), buf, 0, 0, 0) != REG_NOERROR)) { - sd->retryAfter = timer_t1; - } - } - else { - check_socket_error(sock, size); - printf("\nnothing received, select returned error\n"); - exit_code(2, __PRETTY_FUNCTION__, "nothing received, select returned error"); - } - return ret; -} - -/* clears the given sockaddr, fills it with the given data and if a - * socket is given connects the socket to the new target */ -int set_target(struct sockaddr_in *adr, unsigned long target, int port, int socket, int connected) { -#ifdef WITH_TLS_TRANSP - int ret; -# ifdef USE_OPENSSL - int err; - X509* cert; -# endif /* USE_OPENSSL */ -#endif /* WITH_TLS_TRANSP */ - - if (socket != -1 && transport != SIP_UDP_TRANSPORT && connected) { - if (shutdown(socket, SHUT_RDWR) != 0) { - perror("error while shutting down socket"); - } - } - - memset(adr, 0, sizeof(struct sockaddr_in)); - adr->sin_addr.s_addr = target; - adr->sin_port = htons((short)port); - adr->sin_family = AF_INET; - -#ifdef HAVE_INET_NTOP - inet_ntop(adr->sin_family, &adr->sin_addr, &target_dot[0], INET_ADDRSTRLEN); -#endif - - if (socket != -1) { - if (connect(socket, (struct sockaddr *)adr, sizeof(struct sockaddr_in)) == -1) { - perror("connecting socket failed"); - exit_code(2, __PRETTY_FUNCTION__, "connecting socket failed"); - } -#ifdef WITH_TLS_TRANSP - if (transport == SIP_TLS_TRANSPORT) { -# ifdef USE_GNUTLS -# ifdef HAVE_GNUTLS_319 - gnutls_handshake_set_timeout(tls_session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); -# endif - ret = gnutls_handshake(tls_session); - if (ret < 0) { - dbg("TLS Handshake FAILED!!!\n"); - gnutls_perror(ret); - exit_code(3, __PRETTY_FUNCTION__, "TLS handshake failed"); - } - else if (verbose > 2) { - dbg(" TLS Handshake was completed!\n"); - gnutls_session_info(tls_session); - if (verify_certificate_simple(tls_session, domainname) != 0) { - if (ignore_ca_fail == 1) { - if (verbose) { - printf("WARN: Ignoring verification failures of the server certificate\n"); - } - } else { - if (verbose > 1) { - printf("TLS server certificate verification can be ignored with option --tls-ignore-cert-failure.\n"); - } - exit_code(3, __PRETTY_FUNCTION__, "failure during TLS server certificate verification"); - } - } - //verify_certificate_chain(tls_session, domainname, cert_chain, cert_chain_length); - } -# else /* USE_GNUTLS */ -# ifdef USE_OPENSSL - ret = SSL_connect(ssl); - if (ret == 1) { - dbg("TLS connect successful\n"); - if (verbose > 2) { - printf("TLS connect: new connection using %s %s %d\n", - SSL_get_cipher_version(ssl), SSL_get_cipher_name(ssl), - SSL_get_cipher_bits(ssl, 0)); - } - cert = SSL_get_peer_certificate(ssl); - if (cert != 0) { - tls_dump_cert_info("TLS connect: server certificate", cert); - if (SSL_get_verify_result(ssl) != X509_V_OK) { - perror("TLS connect: server certifcate verification failed!!!\n"); - exit_code(3, __PRETTY_FUNCTION__, "TLS server certificate verification falied"); - } - X509_free(cert); - } - else { - perror("TLS connect: server did not present a certificate\n"); - exit_code(3, __PRETTY_FUNCTION__, "missing TLS server certificate"); - } - } - else { - err = SSL_get_error(ssl, ret); - switch (err) { - case SSL_ERROR_ZERO_RETURN: - perror("TLS handshakre failed cleanly'n"); - break; - case SSL_ERROR_WANT_READ: - perror("Need to get more data to finish TLS connect\n"); - break; - case SSL_ERROR_WANT_WRITE: - perror("Need to send more data to finish TLS connect\n"); - break; -#if OPENSSL_VERSION_NUMBER >= 0x00907000L /* 0.9.7 */ - case SSL_ERROR_WANT_CONNECT: - perror("Need to retry connect\n"); - break; - case SSL_ERROR_WANT_ACCEPT: - perror("Need to retry accept'n"); - break; -#endif /* 0.9.7 */ - case SSL_ERROR_WANT_X509_LOOKUP: - perror("Application callback asked to be called again\n"); - break; - case SSL_ERROR_SYSCALL: - printf("TLS connect: %d\n", err); - if (!err) { - if (ret == 0) { - perror("Unexpected EOF occurred while performing TLS connect\n"); - } - else { - printf("IO error: (%d) %s\n", errno, strerror(errno)); - } - } - break; - default: - printf("TLS error: %d\n", err); - } - exit_code(2, __PRETTY_FUNCTION__, "generic SSL error"); - } -# endif /* USE_OPENSSL */ -# endif /* USE_GNUTLS */ - } -#endif /* WITH_TLS_TRANSP */ - } - return 1; -} diff -Nru sipsak-0.9.6+git20170713/transport.h sipsak-0.9.7/transport.h --- sipsak-0.9.6+git20170713/transport.h 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/transport.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2005 Nils Ohlmeier - * - * This file belongs to sipsak, a free sip testing tool. - * - * sipsak is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * sipsak is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef SIPSAK_TRANSPORT_H -#define SIPSAK_TRANSPORT_H - -#include "sipsak.h" -#include "shoot.h" - -#ifdef TIME_WITH_SYS_TIME -# include -# include -#else -# ifdef HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif /* TIME_WITH_SYS_TIME */ -#ifdef HAVE_SYS_SOCKET_H -# include -#endif - -struct sipsak_sr_time { - struct timeval sendtime; - struct timeval recvtime; - struct timeval firstsendt; - struct timeval starttime; - struct timeval delaytime; -}; - -struct sipsak_con_data { - struct sockaddr_in adr; - int csock; - int usock; - int dontsend; - int dontrecv; - int connected; - char *buf_tmp; - int buf_tmp_size; -}; - -struct sipsak_counter { - int send_counter; - int retrans_r_c; - int retrans_s_c; - int randretrys; - int run; -}; - -struct sipsak_delay { - int retryAfter; - double big_delay; - double small_delay; - double all_delay; -}; - -void create_sockets(struct sipsak_con_data *cd); - -void close_sockets(struct sipsak_con_data *cd); - -void send_message(char* mes, struct sipsak_con_data *cd, - struct sipsak_counter *sc, struct sipsak_sr_time *srt); - -void check_socket_error(int socket, int size); - -int check_for_message(char *recv, int size, struct sipsak_con_data *cd, - struct sipsak_sr_time *srt, struct sipsak_counter *count, - struct sipsak_delay *sd); - -int recv_message(char *buf, int size, int inv_trans, - struct sipsak_delay *sd, struct sipsak_sr_time *srt, - struct sipsak_counter *count, struct sipsak_con_data *cd, - struct sipsak_regexp *reg); - -int set_target(struct sockaddr_in *adr, unsigned long target, int port, int socket, int connected); -#endif diff -Nru sipsak-0.9.6+git20170713/.travis.yml sipsak-0.9.7/.travis.yml --- sipsak-0.9.6+git20170713/.travis.yml 2017-07-12 17:05:36.000000000 +0000 +++ sipsak-0.9.7/.travis.yml 2019-04-27 04:54:34.000000000 +0000 @@ -13,6 +13,6 @@ - libc-ares-dev before_install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install check c-ares gnutls ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install check c-ares ; fi install: autoreconf --install script: ./configure && make && make check