├── .github └── workflows │ ├── codeql-analysis.yml │ ├── make_and_check_all_features.yml │ └── make_and_check_basic.yml ├── .gitignore ├── .travis.yml ├── AUTHORS ├── COPYING ├── ChangeLog ├── Makefile.am ├── NEWS ├── README ├── TODO ├── configure.ac ├── indent.pro ├── m4 └── acinclude.m4 ├── sipsak.1 ├── src ├── auth.c ├── auth.h ├── exit_code.c ├── exit_code.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 ├── sip_strings.h ├── sipsak.c ├── sipsak.h ├── transport.c └── transport.h └── tests ├── check_auth.c ├── check_header_f.c ├── check_helper.c └── check_md5.c /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '16 16 * * 2' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | language: [ 'cpp' ] 32 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 33 | # Learn more: 34 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 35 | 36 | steps: 37 | - name: Checkout repository 38 | uses: actions/checkout@v2 39 | 40 | # Initializes the CodeQL tools for scanning. 41 | - name: Initialize CodeQL 42 | uses: github/codeql-action/init@v1 43 | with: 44 | languages: ${{ matrix.language }} 45 | # If you wish to specify custom queries, you can do so here or in a config file. 46 | # By default, queries listed here will override any specified in a config file. 47 | # Prefix the list here with "+" to use these queries and those in the config file. 48 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 49 | 50 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 51 | # If this step fails, then you should remove it and run the build manually (see below) 52 | - name: Autobuild 53 | uses: github/codeql-action/autobuild@v1 54 | 55 | # ℹ️ Command-line programs to run using the OS shell. 56 | # 📚 https://git.io/JvXDl 57 | 58 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 59 | # and modify them (or add more) to build your code if your project 60 | # uses a compiled language 61 | 62 | #- run: | 63 | # make bootstrap 64 | # make release 65 | 66 | - name: Perform CodeQL Analysis 67 | uses: github/codeql-action/analyze@v1 68 | -------------------------------------------------------------------------------- /.github/workflows/make_and_check_all_features.yml: -------------------------------------------------------------------------------- 1 | name: Make/Check with GnuTLS and C-ARES 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build: 11 | 12 | strategy: 13 | matrix: 14 | os: [ ubuntu-latest, ubuntu-18.04, macos-latest, macos-10.15 ] 15 | 16 | runs-on: ${{ matrix.os }} 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | - name: echo runner OS 21 | run: echo "The OS is $RUNNER_OS" 22 | - name: install Linux dependencies 23 | if: runner.os == 'Linux' 24 | run: sudo apt-get install check libc-ares-dev libgnutls28-dev 25 | - name: install macOS dependencies 26 | if: runner.os == 'macOS' 27 | run: brew install automake check c-ares gnutls 28 | - name: autoreconf 29 | run: autoreconf --install 30 | - name: configure 31 | run: ./configure 32 | - name: make 33 | run: make 34 | - name: make check 35 | run: make check 36 | 37 | -------------------------------------------------------------------------------- /.github/workflows/make_and_check_basic.yml: -------------------------------------------------------------------------------- 1 | name: Make/Check w/o 3rd party libs 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build: 11 | 12 | strategy: 13 | matrix: 14 | os: [ ubuntu-latest, ubuntu-18.04, macos-latest, macos-10.15 ] 15 | 16 | runs-on: ${{ matrix.os }} 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | - name: echo runner OS 21 | run: echo "The OS is $RUNNER_OS" 22 | - name: install Linux dependencies 23 | if: runner.os == 'Linux' 24 | run: sudo apt-get install check 25 | - name: install macOS dependencies 26 | if: runner.os == 'macOS' 27 | run: brew install automake check 28 | - name: autoreconf 29 | run: autoreconf --install 30 | - name: configure 31 | run: ./configure 32 | - name: make 33 | run: make 34 | - name: make check 35 | run: make check 36 | 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Autotools 2 | *~ 3 | .deps/ 4 | .dirstamp 5 | INSTALL 6 | Makefile 7 | Makefile.in 8 | aclocal.m4 9 | autom4te.cache/ 10 | compile 11 | config.guess 12 | config.h 13 | config.h.in 14 | config.log 15 | config.status 16 | config.sub 17 | configure 18 | depcomp 19 | install-sh 20 | missing 21 | mkinstalldirs 22 | stamp-h1 23 | test-driver 24 | 25 | # Test suite 26 | *.log 27 | *.trs 28 | 29 | # Programs and objects 30 | *.o 31 | check_helper 32 | check_md5 33 | check_auth 34 | check_header_f 35 | sipsak 36 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | os: 3 | - linux 4 | arch: 5 | - ppc64le 6 | - arm64 7 | compiler: 8 | - clang 9 | - gcc 10 | matrix: 11 | exclude: 12 | - os: linux 13 | compiler: clang 14 | arch: ppc64le 15 | - os: linux 16 | compiler: clang 17 | arch: arm64 18 | include: 19 | - os: osx 20 | osx_image: xcode12.2 21 | sudo: false 22 | addons: 23 | apt: 24 | packages: 25 | - check 26 | - libc-ares-dev 27 | homebrew: 28 | packages: 29 | - check 30 | update: true 31 | install: autoreconf --install 32 | script: 33 | - ./configure && make && make check 34 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # The format of this file was inspired by the Linux kernel CREDITS file. 2 | # 3 | # Authors and contributors are listed alphabetically (first name). 4 | # 5 | # The fields are: name (N), email (E), web-address (W), CVS account login (C), 6 | # PGP key ID and fingerprint (P), description (D), and snail-mail address (S). 7 | 8 | N: Nils Ohlmeier 9 | E: nils@sipsak.org 10 | P: 6CC9F8A1 439A E69B 212C 01E2 2D95 9AAE 636A 3F56 6CC9 F8A1 11 | D: the original author and main developer 12 | 13 | N: Jan Janak 14 | E: jan@iptel.org 15 | D: contributed for example the forking code and several ideas 16 | 17 | N: Jiri Kuthan 18 | E: jiri@iptel.org 19 | D: contributed the exit code code and uncounted bug reports and ideas 20 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | * version 0.9.9 2 | - DNS SRV priority is now supported 3 | * version 0.9.8 4 | - removed support for ruli 5 | - lots of internal refactoring to make sipsak compile with -fno-common (>= gcc-10) 6 | * version 0.9.7 7 | - added new option -E which overrules SRV result 8 | - added new option -J to take ha1 instead of password 9 | - dont retransmit on reliable transports 10 | - added --disable-ips configure option which allows to compile the oldstyle --numeric behavior 11 | - added new option -k only available with TLS support 12 | - added 'star' as special word for the contact option -C 13 | - fixed overwritting of outbound proxy if domainname is an IP; thanks to Alexander Litvak 14 | - added option -Z to modify SIP_T1 at run time 15 | - added syslog support 16 | - enabled -c parameter for Inivte mode 17 | - added new options for TLS (ca-cert, client-cert, ignore-cert-failure) 18 | Note: these options are only available as long options 19 | - added option to ignore TLS certificate verification errors 20 | - added option -k, --local-ip 21 | - added SHA-256 as a possible algorithm for digest authentication 22 | * version 0.9.6 23 | - added new option -j to add a header 24 | - added support for multiple variable replacement (option -g) 25 | - added support for reading password from stdin 26 | - added support for SHA1 as digest algorithm for authentication 27 | - added supoprt for multiple test runs to calculate avarage timming values 28 | - fixed support for cygwin 29 | - fixed using wrong interface and symmetric signaling when running as root 30 | - fixed mem leak when using ares 31 | * version 0.9.5 32 | - added support for TCP transport 33 | - added new option -E to specify the transport 34 | - renamed --invite-timeout to --timeout-after 35 | - added support for c-ares for DNS SRV lookups (http://daniel.haxx.se/projects/c-ares/) 36 | - improved lib ruli detection 37 | - openssl detection is only done when gnutls is missing 38 | - added username to flood mode 39 | - fixed millisecond sleep (thanks to Juri Glass) 40 | - fixed variable replacing (thanks to Todd Ingarfield) 41 | - fixed MD5 detection and compilation 42 | - re-enabled compilation and usage for CygWin 43 | * version 0.9.2 44 | - added new option -D to specify maximum INVITE timeout value 45 | - option -c takes From header for MESSAGE's 46 | - added support for gnutls, which is preferred over openssl now 47 | see configure options --disable-gnutls and --with-libgnutls-prefix 48 | - fixed compilation for Solaris 49 | - fixed ACK building 50 | - fixed several issues with ports and usernames in ruri and outbound proxy 51 | - fixed mis-interpretation of ICMP error messages 52 | - fixed wrong port from SRV entry 53 | - fixed sipsk was still case-sensitive although strcasecmp was available 54 | * version 0.9.1 55 | - added RFC compliant retransmissons of INVITE requests 56 | - fixed compilation errors for BSD and MacOSX 57 | - ACK creation will be rejected for strict routing 58 | - removed obsoleted options from configure 59 | * version 0.9.0 60 | - added new option -S to allow symmetrical signaling in non-root mode 61 | - the option -z now takes an percent argument for the likeliness of binding 62 | removale 63 | - Via contains now branch with magic cookie 64 | - INVITE replies will be answered with ACKs automatically 65 | - basic support for Record-Route and loose routing (strict routing is not 66 | supported yet) 67 | - if an outbound proxy was given it will even be used after being redirected 68 | - request source and destiantion will be printed by -vvv 69 | - the read in file will be checked for conatining an empty line as body 70 | separator 71 | - fixed wrong checking for getopt header in configure 72 | - usage of global functions for memory allocation and integer conversion 73 | - separated the code into several small functions to make it easier 74 | understandable and better mantainable for the future 75 | * version 0.8.13 76 | - nonce count contains the required leading zeros now 77 | - content length is printed as integer and not as hex value 78 | - DNS SRV lookup support through libruli (for target URI, outbound proxy and 79 | redirects) 80 | - all comparisons are now case in-sensitiv if suport by the system 81 | - destination port can be given in the outbound proxy argument 82 | * version 0.8.12 83 | - Nagios compliant return codes (-N) 84 | - use strcasestr if available for case-insensitive compareings 85 | - ACK will be send for 40[17] replies on INVITE 86 | - just return the timing values of the operation (-A) 87 | - relaxed Contact check of option -C 88 | - numeric (-n) is now on by default 89 | * version 0.8.11 90 | - try authentication with empty password instead of username if no 91 | password is given 92 | - support to read SIP message from standard input (-f -) 93 | - insert missing CR in front of LF (-L) 94 | - use different username for authentication (-u) 95 | - use multiple processes for usrloc, message and invite mode (-P) 96 | - search for a string in the reply with a regular expression (-q) 97 | * version 0.8.10 98 | - send instant messages (just -M) 99 | - RFC 3261 compliant retransmission timer 100 | - added From (and To) tags 101 | - use MD5 from openssl if available 102 | - new argument -C to use any given contact value, even empty 103 | - support long options if available 104 | - support Nagios warn level with optional numbers of retransmissions 105 | - use a raw socket if available to support broken RFC 3581 implementations 106 | - small fixes and betaufications 107 | * version 0.8.9 108 | - added Nagios compliant exit codes 109 | - fixed missing replies from un-symmetric servers 110 | - added outbound proxy option 111 | - fixed SIP issues (CSeq increasement on authorization and added missing To and From tags) 112 | * version 0.8.8 113 | - added -p option to use an outbound proxy 114 | - added -C option to use given Contact in REGISTER 115 | - fixed authentication failure when password given as last option 116 | * version 0.8.7 117 | - merged listening and sending socket into one 118 | - added rport parameter to all Via lines 119 | - improved error reporting on host name resolving problems 120 | * version 0.8.6 121 | - fixed wrong number of retries and timeouts from configure 122 | - fixed missing username in default mode 123 | * version 0.8.5 124 | - separated code into several files 125 | - introduced autoconf & automake 126 | - added option -o for sleeping between requests 127 | - added option -H to overwrite automatic hostname detection 128 | - ignores provisional responses in usrloc mode 129 | - added support for proxy authorization (407) 130 | - fixed missing port from uri in requests 131 | - number of retrys is configure option 132 | - maximum timeout value is configure option 133 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 2 | 3 | CC = ${DISTCC} @CC@ 4 | 5 | bin_PROGRAMS = sipsak 6 | 7 | sipsak_SOURCES = src/transport.c src/transport.h 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 src/sip_strings.h 8 | 9 | dist_man1_MANS=sipsak.1 10 | 11 | # Tests 12 | 13 | TESTS = tests/check_md5 tests/check_auth tests/check_helper tests/check_header_f 14 | 15 | check_PROGRAMS = $(TESTS) 16 | 17 | tests_check_md5_SOURCES = tests/check_md5.c src/md5.h src/md5.c 18 | tests_check_md5_CFLAGS = @CHECK_CFLAGS@ -DRUNNING_CHECK 19 | tests_check_md5_LDADD = @CHECK_LIBS@ 20 | 21 | tests_check_auth_SOURCES = tests/check_auth.c src/auth.h src/auth.c src/sipsak.h src/md5.h src/md5.c src/exit_code.h src/helper.h src/helper.c 22 | tests_check_auth_CFLAGS = @CHECK_CFLAGS@ -DRUNNING_CHECK 23 | tests_check_auth_LDADD = @CHECK_LIBS@ 24 | 25 | tests_check_helper_SOURCES = tests/check_helper.c src/helper.h src/helper.c src/exit_code.h src/sipsak.h 26 | tests_check_helper_CFLAGS = @CHECK_CFLAGS@ -DRUNNING_CHECK 27 | tests_check_helper_LDADD = @CHECK_LIBS@ 28 | 29 | tests_check_header_f_SOURCES = tests/check_header_f.c src/header_f.h src/header_f.c src/helper.h src/helper.c 30 | tests_check_header_f_CFLAGS = @CHECK_CFLAGS@ -DRUNNING_CHECK 31 | tests_check_header_f_LDADD = @CHECK_LIBS@ 32 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | * version 0.9.6 2 | - added new option -j to add a header 3 | - added support for multiple variable replacement (option -g) 4 | - added support for SHA1 as digest algorithm for authentication 5 | * version 0.9.5 6 | - renamed --invite-timeout to --timeout-factor 7 | - new option -E specifies the transport (UDP or TCP) 8 | - SRV lookup via c-ares is available 9 | (http://daniel.haxx.se/projects/c-ares/) 10 | * version 0.9.2 11 | - prefers gnutls over openssl now 12 | - new option -D specifies the maximum INVITE timeout value 13 | - option -c specifies From header for MESSAGEs 14 | * version 0.9.1 15 | - only fixes, no new options or features 16 | * version 0.9.0 17 | - option -c in flood mode is replaced be -e 18 | * version 0.8.13 19 | - SRV lookup is supported if libruli is available 20 | (http://www.nongnu.org/ruli/) 21 | * version 0.8.12 22 | - numeric (-n) is now on by default 23 | * version 0.8.11 24 | - try authentication with empty password instead of username if no 25 | password is given 26 | - support to read SIP message from standard input (-f -) 27 | * version 0.8.10 28 | - send instant messages (just -M) 29 | - new argument -C to use any given contact value, even empty 30 | - support long options if available 31 | - support Nagios warn level with optional numbers of retransmissions 32 | * version 0.8.6 33 | - important fixes 34 | * version 0.8.5 35 | - ignores provisional responses in usrloc mode (-U) 36 | - added support for proxy authorization (407) 37 | - new argument -H overwrites automatic hostname detection 38 | - new argument -o introduces sleeping seconds before sending next request 39 | - number of retrys and maximum timeout values are configure options 40 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | REQUIREMENTS 3 | ============ 4 | 5 | None. 6 | 7 | Optional: 8 | - Have 9 | GnuTLS (http://www.gnutls.org/) 10 | or 11 | OpenSSL (http://www.openssl.org/) 12 | installed on your system to use their MD5 implementations 13 | instead of sipsak own version. 14 | - Have 15 | c-ares (http://daniel.haxx.se/projects/c-ares/) 16 | installed on your system to get DNS SRV lookup support 17 | compiled into your sipsak binary. 18 | 19 | INSTALLATION 20 | ============ 21 | 22 | Prerequisites (installed): 23 | - autoconf >= 2.69 24 | - automake 25 | - pkg-config 26 | 27 | The usual: 28 | 29 | autoreconf --install 30 | ./configure 31 | make 32 | 33 | followed by an optional 34 | 35 | make install 36 | 37 | if the binary should be available for all users on that host. 38 | 39 | TESTS 40 | ===== 41 | 42 | Running tests can be done with 43 | 44 | make check 45 | 46 | be sure to have check -- unit test framework for C -- installed 47 | 48 | apt-get install check 49 | yum install check 50 | brew install check 51 | 52 | USAGE 53 | ===== 54 | 55 | Please read the man page. It also contains some typical usage 56 | examples at the end. 57 | 58 | Have fun 59 | Nils Ohlmeier 60 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | ToDo List (no order): 2 | - fix: wrong nonce value after aprox. 2000 users 3 | - fix: after aprox. 3 users the password is missing except -p was set 4 | - add displayname support to parse_uri 5 | - check the request target for the ACK 6 | - add option to tear down INVITED calls with BYE 7 | - add support for CANCEL 8 | - add support for spoofed IPs 9 | - parse the complete DNS resonses in util 10 | - increase hostname detection for the Via line 11 | - add support for priority and weigth in SRV responses 12 | - endless randtrash mode with logfile 13 | - support for IPv6 14 | - strict RR support 15 | 16 | Feel free to send me patches for this (or other) features! 17 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ([2.69]) 5 | AC_INIT([sipsak],[0.9.9-pre],[github@ohlmeier.org]) 6 | AM_INIT_AUTOMAKE([subdir-objects]) 7 | AM_MAINTAINER_MODE 8 | AC_CONFIG_SRCDIR([src/sipsak.c]) 9 | AC_CONFIG_HEADERS([config.h]) 10 | 11 | # Checks for programs. 12 | AC_PROG_CC 13 | # Add -Wall if we are using GCC 14 | if test "x$GCC" = "xyes"; then 15 | CFLAGS="$CFLAGS -Wall" 16 | fi 17 | SIPSAK_GCC_STACK_PROTECT_CC 18 | CHECK_PROG_DISTCC 19 | 20 | AC_PROG_INSTALL 21 | 22 | # Checks for libraries. 23 | AC_CANONICAL_HOST 24 | 25 | # For backwards compatibility with automake < 1.14 26 | AM_PROG_CC_C_O 27 | 28 | # Checks for header files. 29 | AC_CHECK_HEADERS([ctype.h errno.h arpa/inet.h netdb.h netinet/in.h netinet/in_systm.h limits.h sys/poll.h regex.h signal.h stdarg.h stdlib.h stdio.h string.h sys/param.h sys/socket.h sys/time.h unistd.h sys/utsname.h],,[AC_MSG_ERROR([missing required header (see above)])],) 30 | AC_CHECK_HEADERS([getopt.h syslog.h]) 31 | AC_HEADER_SYS_WAIT 32 | AC_CHECK_HEADERS_ONCE([sys/time.h]) 33 | 34 | 35 | SIPSAK_IP_UDP 36 | SIPSAK_ICMP 37 | SIPSAK_RAW_SUPPORT 38 | 39 | # Checks for typedefs, structures, and compiler characteristics. 40 | AC_TYPE_SIZE_T 41 | 42 | # Checks for library functions. 43 | AC_FUNC_MALLOC 44 | AC_FUNC_SELECT_ARGTYPES 45 | 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)])]) 46 | AC_CHECK_FUNCS([calloc getdomainname getopt_long inet_ntop strncasecmp strcasestr syslog]) 47 | 48 | PKG_PROG_PKG_CONFIG 49 | 50 | # Check if the check unit test framework is available 51 | PKG_CHECK_MODULES([CHECK], [check >= 0.9.3], [ 52 | AC_DEFINE([HAVE_CHECK_H], [1], [Has check.h]) 53 | ],:) 54 | 55 | PKG_CHECK_MODULES([GNUTLS], [gnutls >= 1.0.0], [ 56 | AC_DEFINE([HAVE_GNUTLS], [1], [Has gnutls >= 1.0.0]) 57 | HAVE_GNUTLS=1 58 | LIBS="${LIBS} ${GNUTLS_LIBS}" 59 | CFLAGS="${CFLAGS} ${GNUTLS_CFLAGS}" 60 | ], [ 61 | AC_CHECK_HEADERS([openssl/md5.h], [ 62 | AC_SEARCH_LIBS([MD5_Init], [crypto], [ 63 | AC_DEFINE([HAVE_CRYPTO_WITH_MD5], [1], [The crypto lib has MD5 functions]) 64 | ]) 65 | ]) 66 | 67 | AC_CHECK_HEADERS([openssl/sha.h], [ 68 | AC_SEARCH_LIBS([SHA1_Init], [crypto], [ 69 | AC_DEFINE([HAVE_CRYPTO_WITH_SHA1], [1], [The crpyto lib has SHA1 functions]) 70 | ]) 71 | ]) 72 | ]) 73 | PKG_CHECK_MODULES([GNUTLS319], [gnutls >= 3.1.9], [ 74 | AC_DEFINE([HAVE_GNUTLS_319], [1], [Has gntuls >= 3.1.9]) 75 | ],:) 76 | 77 | dnl --- 78 | dnl Check if GnuTLS has SRP support. 79 | dnl --- 80 | if test "$HAVE_GNUTLS" = "1"; then 81 | AC_CHECK_LIB(gnutls, gnutls_srp_verifier, 82 | [ 83 | AC_DEFINE(HAVE_GNUTLS_SRP, 1, [if you have the function gnutls_srp_verifier]) 84 | AC_SUBST(HAVE_GNUTLS_SRP, [1]) 85 | ]) 86 | fi 87 | 88 | 89 | PKG_CHECK_MODULES([CARES], [libcares], [ 90 | AC_DEFINE([HAVE_CARES_H], [1], [Has cares.h]) 91 | LIBS="$LIBS $CARES_LIBS" 92 | CFLAGS="$CFLAGS $CARES_CFLAGS" 93 | AC_CHECK_HEADERS([arpa/nameser.h]) 94 | ],:) 95 | 96 | # FIXME: this has to replaced with a real check 97 | # LIBS="$LIBS -lssl" 98 | 99 | SIPSAK_TIMER 100 | SIPSAK_OLD_FQDN 101 | SIPSAK_TLS 102 | SIPSAK_DBG_PRINT 103 | 104 | AC_CONFIG_FILES([Makefile]) 105 | AC_OUTPUT 106 | -------------------------------------------------------------------------------- /indent.pro: -------------------------------------------------------------------------------- 1 | --blank-lines-after-declarations 2 | --blank-lines-after-procedures 3 | --blank-lines-before-block-comments 4 | --braces-on-func-def-line 5 | --braces-on-if-line 6 | --braces-on-struct-decl-line 7 | --break-after-boolean-operator 8 | --continue-at-parentheses 9 | --continuation-indentation8 10 | --comment-line-length78 11 | --declaration-indentation5 12 | --dont-break-procedure-type 13 | --dont-cuddle-else 14 | --else-endif-column8 15 | --format-first-column-comments 16 | --format-all-comments 17 | --indent-level4 18 | --line-length78 19 | --no-blank-lines-after-commas 20 | --no-space-after-function-call-names 21 | --parameter-indentation0 22 | --preprocessor-indentation1 23 | //--space-after-parentheses 24 | --swallow-optional-blank-lines 25 | --tab-size4 26 | --use-tabs 27 | -------------------------------------------------------------------------------- /m4/acinclude.m4: -------------------------------------------------------------------------------- 1 | AC_DEFUN([SIPSAK_IP_UDP], 2 | [ 3 | AC_CHECK_HEADERS([netinet/ip.h netinet/udp.h],,, 4 | [[#ifdef HAVE_NETINET_IN_SYSTM_H 5 | #include 6 | #include 7 | #include 8 | #endif 9 | ]]) 10 | ]) 11 | 12 | AC_DEFUN([SIPSAK_ICMP], 13 | [ 14 | AC_CHECK_HEADERS([netinet/ip_icmp.h],,, 15 | [[#ifdef HAVE_NETINET_IN_SYSTM_H 16 | #include 17 | #include 18 | #include 19 | #endif 20 | #ifdef HAVE_NETINET_IP_H 21 | #include 22 | #endif 23 | ]]) 24 | ]) 25 | 26 | AC_DEFUN([SIPSAK_RAW_SUPPORT], 27 | [ 28 | AC_REQUIRE([SIPSAK_IP_UDP]) 29 | AC_REQUIRE([SIPSAK_ICMP]) 30 | AC_CHECK_HEADERS([cygwin/icmp.h]) 31 | AC_ARG_ENABLE([raw-support], 32 | AS_HELP_STRING([--disable-raw-support], [compile without raw socket support]), 33 | [sipsak_raw_support=$enable_raw_support], 34 | [sipsak_raw_support=yes]) 35 | AC_MSG_CHECKING([raw socket support]) 36 | AS_IF([test "X$ac_cv_header_netinet_ip_h" = "Xno" || 37 | test "X$ac_cv_header_netinet_ip_icmp_h" = "Xno" || 38 | test "X$ac_cv_header_cygwin_icmp_h" = "Xyes"], [ 39 | sipsak_raw_support=no 40 | ]) 41 | AS_IF([test "X$sipsak_raw_support" = "Xyes"], [ 42 | AC_DEFINE([RAW_SUPPORT], [1], [Define to 1 to use raw socket support]) 43 | ]) 44 | AC_MSG_RESULT([$sipsak_raw_support]) 45 | ]) 46 | 47 | AC_DEFUN([SIPSAK_TIMER], 48 | [ 49 | # Check for T1 timer value 50 | def_timeout=500 51 | AC_ARG_ENABLE([timeout],AS_HELP_STRING(--enable-timeout=SEC,SIP timer T1 in SEC milliseconds (default 500)),[def_timeout=$enableval]) 52 | if test "X$def_timeout" = "Xno"; then 53 | # no timeout makes no sense 54 | def_timeout=500 55 | fi 56 | AC_DEFINE_UNQUOTED(DEFAULT_TIMEOUT, $def_timeout, [Default maximum timeout on waiting for response.]) 57 | ]) 58 | 59 | AC_DEFUN([SIPSAK_OLD_FQDN], 60 | [ 61 | AC_MSG_CHECKING([oldstyle numeric]) 62 | AC_ARG_ENABLE([ips], 63 | AS_HELP_STRING([--disbale-ips], [compile with oldstyle --numeric behavior]), 64 | [ 65 | AC_MSG_RESULT([yes]) 66 | AC_DEFINE([OLDSTYLE_FQDN], [1], [Oldstyle FQDN behavior]) 67 | ], 68 | [ AC_MSG_RESULT([not requested]) 69 | ]) 70 | ]) 71 | 72 | AC_DEFUN([SIPSAK_TLS], 73 | [ 74 | AC_MSG_CHECKING([disable TLS]) 75 | AC_ARG_ENABLE([tls], 76 | AS_HELP_STRING([--disable-tls], [compile without TLS transport]), 77 | [ 78 | AC_MSG_RESULT([yes]) 79 | AC_DEFINE([SIPSAK_NO_TLS], [1], [Skip TLS transport]) 80 | ], 81 | [ AC_MSG_RESULT([not requested]) 82 | ]) 83 | ]) 84 | 85 | AC_DEFUN([SIPSAK_DBG_PRINT], 86 | [ 87 | AC_MSG_CHECKING([enable debug messages]) 88 | AC_ARG_ENABLE([debug], 89 | AS_HELP_STRING([--enable-debug], [compile extra debug messages]), 90 | [ 91 | AC_MSG_RESULT([yes]) 92 | AC_DEFINE([SIPSAK_PRINT_DBG], [1], [Enable debug messages]) 93 | ], 94 | [ AC_MSG_RESULT([not requested]) 95 | ]) 96 | ]) 97 | 98 | AC_DEFUN([CHECK_PROG_DISTCC], 99 | [ 100 | AC_MSG_CHECKING([whether to use distcc]) 101 | AC_ARG_ENABLE([distcc], 102 | AS_HELP_STRING([--enable-distcc], [compile in parallel with distcc]), 103 | [ 104 | AC_MSG_RESULT([yes]) 105 | AC_CHECK_PROG([DISTCC], [distcc]) 106 | ], 107 | [ AC_MSG_RESULT([not requested]) 108 | ]) 109 | ]) 110 | 111 | dnl 112 | dnl Useful macros for autoconf to check for ssp-patched gcc 113 | dnl 1.0 - September 2003 - Tiago Sousa 114 | dnl 115 | dnl About ssp: 116 | dnl GCC extension for protecting applications from stack-smashing attacks 117 | dnl http://www.research.ibm.com/trl/projects/security/ssp/ 118 | dnl 119 | dnl Usage: 120 | dnl After calling the correct AC_LANG_*, use the corresponding macro: 121 | dnl 122 | dnl GCC_STACK_PROTECT_CC 123 | dnl checks -fstack-protector with the C compiler, if it exists then updates 124 | dnl CFLAGS and defines ENABLE_SSP_CC 125 | dnl 126 | dnl GCC_STACK_PROTECT_CXX 127 | dnl checks -fstack-protector with the C++ compiler, if it exists then updates 128 | dnl CXXFLAGS and defines ENABLE_SSP_CXX 129 | dnl 130 | 131 | AC_DEFUN([SIPSAK_GCC_STACK_PROTECT_CC],[ 132 | ssp_cc=yes 133 | if test "X$CC" != "X"; then 134 | AC_MSG_CHECKING([whether ${CC} accepts -fstack-protector]) 135 | ssp_old_cflags="$CFLAGS" 136 | CFLAGS="$CFLAGS -fstack-protector" 137 | AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], [], [], [ssp_cc=no]) 138 | AC_MSG_RESULT([$ssp_cc]) 139 | if test "X$ssp_cc" = "Xno"; then 140 | CFLAGS="$ssp_old_cflags" 141 | else 142 | AC_DEFINE([ENABLE_SSP_CC], 1, [Define if SSP C support is enabled.]) 143 | fi 144 | fi 145 | ]) 146 | 147 | dnl *-*wedit:notab*-* Please keep this as the last line. 148 | -------------------------------------------------------------------------------- /sipsak.1: -------------------------------------------------------------------------------- 1 | .\" Process this file with 2 | .\" groff -man -Tascii sipsak.1 3 | .\" 4 | .TH SIPSAK 1 "JULY 2002 - SEPTEMBER 2005" Linux "User Manuals" 5 | .SH NAME 6 | sipsak \- a utility for various tests on sip servers and user agents 7 | .SH SYNOPSIS 8 | .B sipsak [-dFGhiILnNMRSTUVvwz] [-a 9 | .I PASSWORD 10 | .B ] [-b 11 | .I NUMBER 12 | .B ] [-c 13 | .I SIPURI 14 | .B ] [-C 15 | .I SIPURI 16 | .B ] [-D 17 | .I NUMBER 18 | .B ] [-e 19 | .I NUMBER 20 | .B ] [-E 21 | .I STRING 22 | .B ] [-f 23 | .I FILE 24 | .B ] [-g 25 | .I STRING 26 | .B ] [-H 27 | .I HOSTNAME 28 | .B ] [-j 29 | .I STRING 30 | .B ] [-J 31 | .I STRING 32 | .B ] [-l 33 | .I PORT 34 | .B ] [-m 35 | .I NUMBER 36 | .B ] [-o 37 | .I NUMBER 38 | .B ] [-p 39 | .I HOSTNAME 40 | .B ] [-P 41 | .I NUMBER 42 | .B ] [-q 43 | .I REGEXP 44 | .B ] [-r 45 | .I PORT 46 | .B ] [-t 47 | .I NUMBER 48 | .B ] [-u 49 | .I STRING 50 | .B ] [-W 51 | .I NUMBER 52 | .B ] [-x 53 | .I NUMBER 54 | .B ] -s 55 | .I SIPURI 56 | 57 | .SH DESCRIPTION 58 | .B sipsak 59 | is a SIP stress and diagnostics utility. 60 | It sends SIP requests to the server within the 61 | .BR sip-uri 62 | and examines received responses. 63 | It runs in one of the following modes: 64 | .IP "- default mode" 65 | A SIP message is sent to destination in 66 | .BR sip-uri 67 | and reply status is displayed. 68 | The request is either taken from 69 | .BR filename 70 | or generated as a new OPTIONS message. 71 | .IP "- traceroute mode (-T)" 72 | This mode is useful for learning request's path. It 73 | operates similarly to IP-layer utility 74 | .BR traceroute (8). 75 | .IP "- message mode (-M)" 76 | Sends a short message (similar to SMS from the mobile phones) to a given target. With the option 77 | .BR -B 78 | the content of the MESSAGE can be set. Useful might be the options 79 | .BR -c 80 | and 81 | .BR -O 82 | in this mode. 83 | .IP "- usrloc mode (-U)" 84 | Stress mode for SIP registrar. 85 | .B sipsak 86 | keeps registering to a SIP server at high pace. Additionally the registrar 87 | can be stressed with the 88 | .BR -I 89 | or the 90 | .BR -M 91 | option. 92 | If 93 | .BR -I 94 | and 95 | .BR -M 96 | are omitted 97 | .B sipsak 98 | can be used to register any given contact (with the 99 | .BR -C 100 | option) for an account at a registrar and to query the current bindings for 101 | an account at a registrar. 102 | .IP "- randtrash mode (-R)" 103 | Parser torture mode. 104 | .B sipsak 105 | keeps sending randomly corrupted messages to torture a SIP server's 106 | parser. 107 | .IP "- flood mode (-F)" 108 | Stress mode for SIP servers. 109 | .B sipsak 110 | keeps sending requests to a SIP server at high pace. 111 | 112 | .PP 113 | If c-ares 114 | (http://daniel.haxx.se/projects/c-ares/) support is compiled into the 115 | .B sipsak 116 | binary, then first a SRV lookup for _sip._tcp.hostname is made. If that 117 | fails a SRV lookup for _sip._udp.hostname is made. And if this 118 | lookup fails a normal A lookup is made. If a port was given in the target 119 | URI the SRV lookup is omitted. Failover, load distribution and other 120 | transports are not supported yet. 121 | 122 | .SH OPTIONS 123 | .IP "-a, --password PASSWORD" 124 | With the given 125 | .I PASSWORD 126 | an authentication will be tried on received '401 Unauthorized'. Authorization 127 | will be tried on time. If this option is omitted an authorization with an 128 | empty password ("") will be tried. If the password is equal to 129 | .I - 130 | the password will be read from the standard input (e.g. the keyboard). This 131 | prevents other users on the same host from seeing the password 132 | in the process list. 133 | .B NOTE: 134 | the password still can be read from the memory if other users have access to 135 | it. 136 | 137 | .IP "-A, --timing" 138 | prints only the timing values of the test run if verbosity is zero because no 139 | .BR -v 140 | was given. If one or more 141 | .BR -v 142 | were given this option will be ignored. 143 | 144 | .IP "-b, --appendix-begin NUMBER" 145 | The starting number which is appended to the user name in the usrloc mode. 146 | This 147 | .I NUMBER 148 | is increased until it reaches the value given by the 149 | .BR -e 150 | parameter. If omitted the starting number will be one. 151 | 152 | .IP "-B, --message-body STRING" 153 | The given 154 | .I STRING 155 | will be used as the body for outgoing MESSAGE requests. 156 | 157 | .IP "-c, --from SIPURI" 158 | The given 159 | .I SIPURI 160 | will be used in the From header if 161 | .B sipsak 162 | runs in the message mode (initiated with the 163 | .BR -M 164 | option). This is helpful to present the receiver of a MESSAGE a meaningful 165 | and usable address to where maybe even responses can be sent. 166 | 167 | .IP "-C, --contact SIPURI" 168 | This is the content of the Contact header in the usrloc mode. This allows 169 | to insert forwards like for mail. For example you can insert the uri of 170 | your first SIP account at a second account, thus all calls to the second 171 | account will be forwarded to the first account. 172 | As the argument to this option will not be enclosed in brackets you can 173 | give also multiple contacts in the raw format as comma separated list. 174 | The special words 175 | .B empty 176 | or 177 | .B none 178 | will result in no contact header in the REGISTER request and thus the server 179 | should answer with the current bindings for the account at the registrar. 180 | The special words 181 | .B * 182 | or 183 | .B star 184 | will result in Contact header containing just a star, e.g. to remove all 185 | bindings by using expires value 0 together with this Contact. 186 | 187 | .IP "-d, --ignore-redirects" 188 | If this option is set all redirects will be ignored. By default without this 189 | option received redirects will be respected. This option is automatically 190 | activated in the randtrash mode and in the flood mode. 191 | 192 | .IP "-D, --timeout-factor NUMBER" 193 | The SIP_T1 timer is getting multiplied with the given NUMBER. After receiving 194 | a provisional response for an INVITE request, or when a reliable transport 195 | like TCP or TLS is used 196 | .B sipsak 197 | waits for the resulting amount of time for a final response until it gives up. 198 | 199 | .IP "-e, --appendix-end NUMBER" 200 | The ending number which is appended to the user name in the usrloc mode. 201 | This number is increased until it reaches this ending 202 | .I number. 203 | In the flood mode this is the maximum number of messages which will be sent. 204 | If omitted the default value is 2^31 (2147483647) in the flood mode. 205 | 206 | .IP "-E, --transport STRING" 207 | The value of 208 | .I STRING 209 | will be used as IP transport for sending and receiving requests and responses. 210 | This option overwrites any result from the URI evaluation and SRV lookup. 211 | Currently only 'udp' and 'tcp' are accepted as value for 212 | .I STRING. 213 | 214 | .IP "-f, --filename FILE" 215 | The content of 216 | .I FILE 217 | will be read in in binary mode and will be used as replacement for the 218 | alternatively created sip message. This can used in the default mode to make 219 | other requests than OPTIONS requests (e.g. INVITE). By default missing 220 | carriage returns in front of line feeds will be inserted (use 221 | .BR -L 222 | to de-activate this function). If the filename is equal to 223 | .I - 224 | the file is read from standard input, e.g. from the keyboard or a pipe. 225 | Please note that the manipulation functions (e.g. inserting Via header) 226 | are only tested with RFC conform requests. Additionally special strings 227 | within the file can be replaced with some local or given values (see 228 | .BR -g 229 | and 230 | .BR -G 231 | for details). 232 | 233 | .IP "-F, --flood-mode" 234 | This option activates the flood mode. In this mode OPTIONS requests with 235 | increasing CSeq numbers are sent to the server. Replies are ignored -- 236 | source port 9 (discard) of localhost is advertised in topmost Via. 237 | 238 | .IP "-h, --help" 239 | Prints out a simple usage help message. If the long option 240 | .BR --help 241 | is available it will print out a help message with the available long options. 242 | 243 | .IP "-g, --replace-string STRING" 244 | Activates the replacement of $replace$ within the request (usually read 245 | in from a file) with the 246 | .I STRING. 247 | Alternatively you can also specify a list of attributes and values. 248 | This list has to start and end with a non alpha-numeric character. The 249 | same character has to be used also as separator between the attribute and 250 | the value and between new further attribute value pairs. The string 251 | "$attribute$" will be replaced with the value string in the message. 252 | 253 | .IP "-G, --replace" 254 | Activates the automatic replacement of the following variables in the 255 | request (usually read in from a file): 256 | .B $dsthost$ 257 | will be replaced with the host or domainname which is given 258 | by the 259 | .B -s 260 | parameter. 261 | .B $srchost$ 262 | will be replaced by the hostname of the local machine. 263 | .B $port$ 264 | will be replaced by the local listening port of 265 | .B sipsak. 266 | .B $user$ 267 | will be replaced by the username which is given by the 268 | .B -s 269 | parameter. 270 | 271 | .IP "-H, --hostname HOSTNAME" 272 | Overwrites the automatic detection of the hostname with the given parameter. 273 | .B Warning: 274 | use this with caution (preferable only if the automatic detection fails). 275 | 276 | .IP "-i, --no-via" 277 | Deactivates the insertion of the Via line of the localhost. 278 | .B Warning: 279 | this probably disables the receiving of the responses from the server. 280 | 281 | .IP "-I, --invite-mode" 282 | Activates the Invites cycles within the usrloc mode. It should be combined 283 | with 284 | .BR -U. 285 | In this combination 286 | .B sipsak 287 | first registers a user, and then simulates an 288 | invitation to this user. First an Invite is sent, this is replied with 200 OK 289 | and finally an ACK is sent. This option can also be used without 290 | .BR -U 291 | , but you should be sure to NOT invite real UAs with this option. In the case 292 | of a missing 293 | .BR -U 294 | the 295 | .BR "-l PORT" 296 | is required because only if you made a 297 | .BR -U 298 | run with a fixed local port before, a run with 299 | .BR -I 300 | and the same fixed local port can be successful. 301 | .B Warning: sipsak 302 | is no real UA and invitations to real UAs can result in unexpected 303 | behaviour. 304 | 305 | .IP "-j, --headers STRING" 306 | The 307 | .BR string 308 | will be added as one or more additional headers to the request. The string 309 | "\\n" (note: two characters) will be replaced with CRLF and thus result 310 | in two separate headers. That way more then one header can be added. 311 | 312 | .IP "-J, --autohash STRING" 313 | The 314 | .BR string 315 | will be used as the H(A1) input to the digest authentication response 316 | calculation. Thus no password from the 317 | .BR -a 318 | option is required if this option is provided. The given 319 | .BR string 320 | is expected to be a hex string with the length of the used hash function. 321 | 322 | .IP "-k, --local-ip STRING" 323 | The local ip address to be used 324 | 325 | .IP "-l, --local-port PORT" 326 | The receiving UDP socket will use the local network 327 | .I port. 328 | Useful if a file is given by 329 | .BR -f 330 | which contains a correct Via line. Check the 331 | .BR -S 332 | option for details how sipsak sends and receives messages. 333 | 334 | .IP "-L, --no-crlf" 335 | De-activates the insertion of carriage returns (\\r) before all line feeds 336 | (\\n) (which is not already proceeded by carriage return) if the input 337 | is coming from a file ( 338 | .BR -f 339 | ). Without this option also an empty line will be appended to the request 340 | if required. 341 | 342 | .IP "-m, --max-forwards NUMBER" 343 | This sets the value of the Max-Forward header field. If omitted no Max-Forward 344 | field will be inserted. If omitted in the traceroute mode 345 | .BR number 346 | will be 255. 347 | 348 | .IP "-M, --message-mode" 349 | This activates the Messages cycles within the usrloc mode (known from 350 | .B sipsak 351 | versions pre 0.8.0 within the normal usrloc test). This option should be 352 | combined with 353 | .BR -U 354 | so that a successful registration will be tested with a test message to the user 355 | and replied with 200 OK. But this option can also be used without the 356 | .BR -U 357 | option. 358 | .B Warning: 359 | using without 360 | .BR -U 361 | can cause unexpected behavior. 362 | 363 | .IP "-n, --numeric" 364 | Instead of the full qualified domain name in the Via line the IP of the 365 | local host will be used. This option is now on by default. 366 | 367 | .IP "-N, --nagios-code" 368 | Use Nagios compliant return codes instead of the normal sipsak ones. This means 369 | .B sipsak 370 | will return 0 if everything was ok and 2 in case of any error (local or remote). 371 | 372 | .IP "-o, --sleep NUMBER" 373 | .B sipsak 374 | will sleep for 375 | .BR NUMBER 376 | ms before it starts the next cycle in the usrloc mode. This will slow down 377 | the whole test process to be more realistic. Each cycle will be still completed 378 | as fast as possible, but the whole test will be slowed down. 379 | 380 | .IP "-O, --disposition STRING" 381 | The given 382 | .BR STRING 383 | will be used as the content for the Content-Disposition header. Without this 384 | option there will be no Content-Disposition header in the request. 385 | 386 | .IP "-p, --outbound-proxy HOSTNAME[:PORT]" 387 | the address of the hostname is the target where the request will be sent to 388 | (outgoing proxy). Use this if the destination host is different from the host 389 | part of the request uri. The hostname is resolved via DNS SRV if supported 390 | (see description for SRV resolving) and no port is given. 391 | 392 | .IP "-P, --processes NUMBER" 393 | Start 394 | .BR NUMBER 395 | of processes in parallel to do the send and reply checking. Only makes sense 396 | if a higher number for 397 | .BR -e 398 | is given in the usrloc, message or invite mode. 399 | 400 | .IP "-q, --search REGEXP" 401 | match replies against 402 | .BR REGEXP 403 | and return false if no match 404 | occurred. Useful for example to detect server name in Server header field. 405 | 406 | .IP "-r, --remote-port PORT" 407 | Instead of the default sip port 5060 the 408 | .BR PORT 409 | will be used. Alternatively the remote port can be given within the sip uri of 410 | the 411 | .BR -s 412 | parameter. 413 | 414 | .IP "-R, --random-mode" 415 | This activates the randtrash mode. In this mode OPTIONS requests will be sent 416 | to server with increasing numbers of randomly crashed characters within this 417 | request. The position within the request and the replacing character are 418 | randomly chosen. Any other response than Bad request (4xx) will stop this 419 | mode. Also three unresponded sends will stop this mode. With the 420 | .BR -t 421 | parameter the maximum of trashed characters can be given. 422 | 423 | .IP "-s, --sip-uri SIPURI" 424 | This mandatory option sets the destination of the request. It depends on the 425 | mode if only the server name or also a user name is mandatory. Example for a 426 | full 427 | .BR SIPURI 428 | : 429 | .I sip:test@foo.bar:123 430 | See the note in the description part about SRV lookups for details how the 431 | hostname of this URI is converted into an IP and port. 432 | 433 | .IP "-S, --symmetric" 434 | With this option 435 | .B sipsak 436 | will use only one port for sending and receiving messages. With this option 437 | the local port for sending will be the value from the 438 | .BR -l 439 | option. In the default mode 440 | .B sipsak 441 | sends from a random port and listens on the given port from the 442 | .BR -l 443 | option. 444 | .B Note: 445 | With this option 446 | .B sipsak 447 | will not be able to receive replies from servers with asymmetric signaling 448 | (and broken rport implementation) like the Cisco proxy. If you run 449 | .B sipsak 450 | as root and with raw socket support (check the output from the 451 | .BR -V 452 | option) then this option is not required because in this case 453 | .B sipsak 454 | already uses only one port for sending and receiving messages. 455 | 456 | .IP "-t, --trash-chars NUMBER" 457 | This parameter specifies the maximum of trashed characters in the randtrash 458 | mode. If omitted 459 | .BR NUMBER 460 | will be set to the length of the request. 461 | 462 | .IP "-T, --traceroute-mode" 463 | This activates the traceroute mode. This mode works like the well known 464 | .BR traceroute(8) 465 | command expect that not the number of network hops is counted rather 466 | the number of servers on the way to the destination user. Also the round trip 467 | time of each request is printed out, but due to a limitation within the 468 | sip protocol the identity (IP or name) can only be determined and printed 469 | out if the response from the server contains a warning header field. In this 470 | mode on each outgoing request the value of the Max-Forwards header field is 471 | increased, starting with one. The maximum of the Max-Forwards header will be 255 472 | if no other value is given by the 473 | .BR -m 474 | parameter. Any other response than 483 or 1xx is treated as a final response 475 | and will terminate this mode. 476 | 477 | .IP "-u, --auth-username STRING" 478 | Use the given 479 | .BR STRING 480 | as username value for the authentication (different account and 481 | authentication username). 482 | 483 | .IP "-U, --usrloc-mode" 484 | This activates the usrloc mode. Without the 485 | .BR -I 486 | or the 487 | .BR -M 488 | option, this only registers users at a registrar. With one of the above 489 | options the previous registered user will also be probed, wether with a 490 | simulated call flow (invite, 200, ack) or with an instant message 491 | (message, 200). One password for all users accounts within the usrloc test 492 | can be given with the 493 | .BR -a 494 | option. A user name is mandatory for this mode in the 495 | .BR -s 496 | parameter. The number starting from the 497 | .BR -b 498 | parameter to the 499 | .BR -e 500 | parameter is appended the user name. If the 501 | .BR -b 502 | and the 503 | .BR -e 504 | parameter are omitted, only one run with the given username, but without 505 | append number to the usernames is done. 506 | 507 | .IP "-v, --verbose" 508 | This parameter increases the output verbosity. No 509 | .BR -v 510 | means nearly no output except in traceroute and error messages. The maximum 511 | of three v's prints out the content of all packets received and sent. 512 | 513 | .IP "-V, --version" 514 | Prints out the name and version number of 515 | .B sipsak 516 | and the options which were compiled into the binary. 517 | 518 | .IP "-w, --extract-ip" 519 | Activates the extraction of the IP or hostname from the Warning header field. 520 | 521 | .IP "-W, --nagios-warn NUMBER" 522 | Return Nagios warn exit code (1) if the number of retransmissions before 523 | success was above the given number. 524 | 525 | .IP "-x, --expires NUMBER" 526 | Sets the value of the Expires header to the given number. 527 | 528 | .IP "-z, --remove-bindings" 529 | Activates the randomly removing of old bindings in the usrloc mode. How many 530 | percent of the bindings will be removed, is determined by the 531 | USRLOC_REMOVE_PERCENT define within the code (set it before compilation). 532 | Multiple removing of bindings is possible, and cannot be prevented. 533 | 534 | .IP "-Z, --timer-t1" 535 | Sets the amount of milliseconds for the SIP timer T1. It determines the 536 | length of the gaps between two retransmissions of a request on a unreliable 537 | transport. Default value is 500 if not changed via the configure option 538 | --enable-timeout. 539 | 540 | .SH RETURN VALUES 541 | The return value 0 means that a 200 was received. 1 means something else 542 | than 1xx or 2xx was received. 543 | 2 will be returned on local errors like non resolvable names or 544 | wrong options combination. 3 will be returned on remote errors like socket 545 | errors (e.g. icmp error), redirects without a contact header or simply 546 | no answer (timeout). 547 | 548 | If the 549 | .BR -N 550 | option was given the return code will be 2 in case of any (local or remote) 551 | error. 1 in case there have been retransmissions from 552 | .B sipsak 553 | to the server. And 0 if there was no error at all. 554 | .SH CAUTION 555 | Use 556 | .B sipsak 557 | responsibly. Running it in any of the stress modes puts 558 | substantial burden on network and server under test. 559 | 560 | .SH EXAMPLES 561 | .IP "sipsak -vv -s sip:nobody@foo.bar" 562 | displays received replies. 563 | .IP "sipsak -T -s sip:nobody@foo.bar" 564 | traces SIP path to nobody. 565 | .IP "sipsak -U -C sip:me@home -x 3600 -a password -s sip:myself@company" 566 | inserts forwarding from work to home for one hour. 567 | .IP "sipsak -f bye.sip -g '!FTAG!345.af23!TTAG!1208.12!' -s sip:myproxy" 568 | reads the file bye.sip, replaces $FTAG$ with 345.af23 and $TTAG$ with 569 | 1208.12 and finally send this message to myproxy 570 | 571 | .SH LIMITATIONS / NOT IMPLEMENTED 572 | Many servers may decide NOT to include SIP "Warning" header fields. 573 | Unfortunately, this makes displaying IP addresses of SIP servers 574 | in traceroute mode impossible. 575 | 576 | IPv6 is not supported. 577 | 578 | Missing support for the Record-Route and Route header. 579 | 580 | .SH BUGS 581 | sipsak is only tested against the SIP Express Router (ser) though their could 582 | be various bugs. Please feel free to mail them to the author. 583 | 584 | 585 | .SH AUTHOR 586 | Nils Ohlmeier 587 | .SH "SEE ALSO" 588 | .BR traceroute (8) 589 | -------------------------------------------------------------------------------- /src/auth.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2002-2004 Fhg Fokus 3 | * Copyright (C) 2004-2022 Nils Ohlmeier 4 | * 5 | * This file belongs to sipsak, a free sip testing tool. 6 | * 7 | * sipsak is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * sipsak is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | #include "sipsak.h" 18 | #include "auth.h" 19 | #include "exit_code.h" 20 | #include "helper.h" 21 | #include "md5.h" 22 | #include "sip_strings.h" 23 | 24 | #ifdef HAVE_OPENSSL_SHA1 25 | # include 26 | #endif 27 | 28 | #if defined(RUNNING_CHECK) && !defined(HAVE_CHECK_H) 29 | #error Missing check unit test framework! 30 | #endif 31 | 32 | #define SIPSAK_ALGO_MD5 1 33 | #define SIPSAK_ALGO_SHA1 2 34 | #define SIPSAK_ALGO_SHA256 3 35 | 36 | unsigned int nonce_count; 37 | 38 | /* converts a hash into hex output 39 | taken from the RFC 2617 */ 40 | void cvt_hex(unsigned char *_b, unsigned char *_h, unsigned short length) 41 | { 42 | unsigned short i; 43 | 44 | for (i = 0; i < length; i++) { 45 | unsigned char j; 46 | j = (_b[i] >> 4) & 0xf; 47 | if (j <= (unsigned char)9) { 48 | _h[i * 2] = (j + (unsigned char)'0'); 49 | } else { 50 | _h[i * 2] = (unsigned char)(j + (unsigned char)'a' - (unsigned char)10); 51 | } 52 | j = _b[i] & 0xf; 53 | if (j <= (unsigned char)9) { 54 | _h[i * 2 + 1] = (j + (unsigned char)'0'); 55 | } else { 56 | _h[i * 2 + 1] = (unsigned char)(j + (unsigned char)'a' - (unsigned char)10); 57 | } 58 | }; 59 | _h[2*length] = '\0'; 60 | } 61 | 62 | /* check for, create and insert a auth header into the message */ 63 | void insert_auth(char *message, char *authreq, char *username, 64 | char *password, char *auth_username, char *authhash, 65 | int namebeg, int nameend) 66 | { 67 | char *auth, *begin, *end, *insert, *backup, *realm, *usern, *nonce; 68 | char *method, *uri; 69 | char *qop_tmp = NULL; 70 | unsigned char ha1[SIPSAK_HASHLEN], ha2[SIPSAK_HASHLEN], resp[SIPSAK_HASHLEN]; 71 | unsigned char ha1_hex[SIPSAK_HASHHEXLEN+1], ha2_hex[SIPSAK_HASHHEXLEN+1], resp_hex[SIPSAK_HASHHEXLEN+1]; 72 | int qop_auth=0, proxy_auth=0, algo=0; 73 | MD5_CTX Md5Ctx; 74 | #ifdef HAVE_OPENSSL_SHA1 75 | SHA_CTX Sha1Ctx; 76 | SHA256_CTX Sha256Ctx; 77 | #endif 78 | 79 | auth=begin=end=insert=backup=realm=usern=nonce=method=uri = NULL; 80 | 81 | memset(&ha1[0], '\0', SIPSAK_HASHLEN); 82 | memset(&ha2[0], '\0', SIPSAK_HASHLEN); 83 | memset(&resp[0], '\0', SIPSAK_HASHLEN); 84 | memset(&ha1_hex[0], '\0', SIPSAK_HASHHEXLEN+1); 85 | memset(&ha2_hex[0], '\0', SIPSAK_HASHHEXLEN+1); 86 | memset(&resp_hex[0], '\0', SIPSAK_HASHHEXLEN+1); 87 | 88 | /* prevent double auth insertion */ 89 | if ((begin=STRCASESTR(message, AUTH_STR))!=NULL || 90 | (begin=STRCASESTR(message, PROXYAUZ_STR))!=NULL) { 91 | fprintf(stderr, "request:\n%s\nresponse:\n%s\nerror: authorization failed\n " 92 | " request already contains (Proxy-) Authorization, but " 93 | "received 40[1|7], see above\n", message, authreq); 94 | exit_code(2, __PRETTY_FUNCTION__, "failed to add auth header, because request contained already one"); 95 | } 96 | /* make a backup of all except the request line because for 97 | simplicity we insert the auth header direct behind the request line */ 98 | insert=strchr(message, '\n'); 99 | if (!insert) { 100 | fprintf(stderr, "%s\nerror: failed to locate new line in request message\n", 101 | message); 102 | exit_code(3, __PRETTY_FUNCTION__, "missing new line in request"); 103 | } 104 | insert++; 105 | backup=str_alloc(strlen(insert)+1); 106 | strncpy(backup, insert, strlen(insert)); 107 | 108 | begin=STRCASESTR(authreq, WWWAUTH_STR); 109 | if (begin==NULL) { 110 | begin=STRCASESTR(authreq, PROXYAUTH_STR); 111 | proxy_auth = 1; 112 | } 113 | if (begin) { 114 | /* make a copy of the auth header to prevent that our searches 115 | hit content of other header fields */ 116 | end=strchr(begin, '\n'); 117 | if (end == NULL) { 118 | fprintf(stderr, "%s\nerror: failed to locate new line after auth header\n", 119 | authreq); 120 | exit_code(3, __PRETTY_FUNCTION__, "missing new line after auth header"); 121 | } 122 | auth=str_alloc((size_t)(end-begin+1)); 123 | strncpy(auth, begin, (size_t)(end-begin)); 124 | /* we support Digest with MD5 or SHA1 */ 125 | if ((begin=STRCASESTR(auth, "Basic"))!=NULL) { 126 | fprintf(stderr, "%s\nerror: authentication method Basic is deprecated since" 127 | " RFC 3261 and not supported by sipsak\n", authreq); 128 | exit_code(3, __PRETTY_FUNCTION__, "authentication method 'Basic' is deprecated"); 129 | } 130 | if ((begin=STRCASESTR(auth, "Digest"))==NULL) { 131 | fprintf(stderr, "%s\nerror: couldn't find authentication method Digest in " 132 | "the 40[1|7] response above\n", authreq); 133 | exit_code(3, __PRETTY_FUNCTION__, "missing authentication method 'Digest' in reply"); 134 | } 135 | if ((begin=STRCASESTR(auth, "algorithm="))!=NULL) { 136 | begin+=10; 137 | if ((STRNCASECMP(begin, "MD5", 3))==0 || (STRNCASECMP(begin, "\"MD5\"", 5))==0) { 138 | algo = SIPSAK_ALGO_MD5; 139 | } 140 | #ifdef HAVE_OPENSSL_SHA1 141 | else if ((STRNCASECMP(begin, "SHA1", 4))==0 || (STRNCASECMP(begin, "\"SHA1\"", 6))==0) { 142 | algo = SIPSAK_ALGO_SHA1; 143 | } 144 | else if ((STRNCASECMP(begin, "SHA-256", 7))==0 || (STRNCASECMP(begin, "\"SHA-256\"", 9))==0) { 145 | algo = SIPSAK_ALGO_SHA256; 146 | } 147 | #endif 148 | else { 149 | fprintf(stderr, "\n%s\nerror: unsupported authentication algorithm\n", authreq); 150 | exit_code(2, __PRETTY_FUNCTION__, "unsupported authentication algorithm"); 151 | } 152 | } 153 | else { 154 | algo = SIPSAK_ALGO_MD5; 155 | } 156 | /* we need the username at some points */ 157 | if (auth_username != NULL) { 158 | usern = auth_username; 159 | } 160 | else { 161 | usern=str_alloc(strlen(username)+11); 162 | if (usern == NULL) { 163 | fprintf(stderr, "error: failed to allocate space for username: %s\n", 164 | username); 165 | exit_code(3, __PRETTY_FUNCTION__, "memory allocation failure"); 166 | } 167 | if (nameend>0) 168 | snprintf(usern, strlen(username)+10, "%s%d", username, namebeg); 169 | else 170 | snprintf(usern, strlen(username)+1, "%s", username); 171 | } 172 | /* extract the method from the original request */ 173 | end=strchr(message, ' '); 174 | if (end == NULL) { 175 | fprintf(stderr, "%s\nerror: failed to locate space in message first line\n", 176 | authreq); 177 | exit_code(3, __PRETTY_FUNCTION__, "missing space in message"); 178 | } 179 | method=str_alloc((size_t)(end-message+1)); 180 | strncpy(method, message, (size_t)(end-message)); 181 | /* extract the uri also */ 182 | begin=end++; 183 | begin++; 184 | end=strchr(end, ' '); 185 | if (end == NULL) { 186 | fprintf(stderr, "%s\nerror: failed to locate space in message first line\n", 187 | authreq); 188 | exit_code(3, __PRETTY_FUNCTION__, "missing space in message"); 189 | } 190 | uri=str_alloc((size_t)(end-begin+1)); 191 | strncpy(uri, begin, (size_t)(end-begin)); 192 | 193 | /* lets start with some basic stuff... username, uri and algorithm */ 194 | if (proxy_auth == 1) { 195 | snprintf(insert, PROXYAUZ_STR_LEN+1, PROXYAUZ_STR); 196 | insert+=PROXYAUZ_STR_LEN; 197 | } 198 | else { 199 | snprintf(insert, AUTH_STR_LEN+1, AUTH_STR); 200 | insert+=AUTH_STR_LEN; 201 | } 202 | snprintf(insert, strlen(usern)+14, "username=\"%s\", ", usern); 203 | insert+=strlen(insert); 204 | snprintf(insert, strlen(uri)+9, "uri=\"%s\", ", uri); 205 | insert+=strlen(insert); 206 | snprintf(insert, ALGO_STR_LEN+1, ALGO_STR); 207 | insert+=ALGO_STR_LEN; 208 | if (algo == SIPSAK_ALGO_MD5) { 209 | snprintf(insert, MD5_STR_LEN+1, MD5_STR); 210 | insert+=MD5_STR_LEN; 211 | } 212 | #ifdef HAVE_OPENSSL_SHA1 213 | else if (algo == SIPSAK_ALGO_SHA1) { 214 | snprintf(insert, SHA1_STR_LEN+1, SHA1_STR); 215 | insert+=SHA1_STR_LEN; 216 | } 217 | else if (algo == SIPSAK_ALGO_SHA256) { 218 | snprintf(insert, SHA256_STR_LEN+1, SHA256_STR); 219 | insert+=SHA256_STR_LEN; 220 | } 221 | #endif 222 | /* search for the realm, copy it to request and extract it for hash*/ 223 | if ((begin=STRCASESTR(auth, REALM_STR))!=NULL) { 224 | end=strchr(begin, ','); 225 | if (!end) 226 | end=strchr(begin, '\r'); 227 | strncpy(insert, begin, (size_t)(end-begin+1)); 228 | insert=insert+(end-begin+1); 229 | if (*(insert-1) == '\r') 230 | *(insert-1)=','; 231 | snprintf(insert, 2, " "); 232 | insert++; 233 | begin+=REALM_STR_LEN+1; 234 | end--; 235 | realm=str_alloc((size_t)(end-begin+1)); 236 | strncpy(realm, begin, (size_t)(end-begin)); 237 | } 238 | else { 239 | fprintf(stderr, "%s\nerror: realm not found in 401 above\n", authreq); 240 | exit_code(3, __PRETTY_FUNCTION__, "realm not found in reply"); 241 | } 242 | /* copy opaque if needed */ 243 | if ((begin=STRCASESTR(auth, OPAQUE_STR))!=NULL) { 244 | end=strchr(begin, ','); 245 | if (!end) { 246 | end=strchr(begin, '\r'); 247 | } 248 | strncpy(insert, begin, (size_t)(end-begin+1)); 249 | insert=insert+(end-begin+1); 250 | if (*(insert-1) == '\r') 251 | *(insert-1)=','; 252 | snprintf(insert, 2, " "); 253 | insert++; 254 | } 255 | /* lets see if qop=auth is uspported */ 256 | if ((begin=STRCASESTR(auth, QOP_STR))!=NULL) { 257 | if (STRCASESTR(begin, QOPAUTH_STR)==NULL) { 258 | fprintf(stderr, "response\n%s\nerror: qop \"auth\" not supported by" 259 | " server\n", authreq); 260 | exit_code(3, __PRETTY_FUNCTION__, "qop 'auth' is not supported by server"); 261 | } 262 | qop_auth=1; 263 | } 264 | /* search, copy and extract the nonce */ 265 | if ((begin=STRCASESTR(auth, NONCE_STR))!=NULL) { 266 | end=strchr(begin, ','); 267 | if (!end) 268 | end=strchr(begin, '\r'); 269 | strncpy(insert, begin, (size_t)(end-begin+1)); 270 | insert=insert+(end-begin+1); 271 | if (*(insert-1) == '\r') 272 | *(insert-1)=','; 273 | snprintf(insert, 2, " "); 274 | insert++; 275 | begin+=NONCE_STR_LEN+1; 276 | end--; 277 | nonce=str_alloc((size_t)(end-begin+1)); 278 | strncpy(nonce, begin, (size_t)(end-begin)); 279 | } 280 | else { 281 | fprintf(stderr, "%s\nerror: nonce not found in 401 above\n", authreq); 282 | exit_code(3, __PRETTY_FUNCTION__, "missing nonce in reply"); 283 | } 284 | /* if qop is supported we need som additional header */ 285 | if (qop_auth == 1) { 286 | unsigned int cnonce; 287 | snprintf(insert, QOP_STR_LEN+QOPAUTH_STR_LEN+3, "%s%s, ", QOP_STR, QOPAUTH_STR); 288 | insert+=strlen(insert); 289 | nonce_count++; 290 | snprintf(insert, NC_STR_LEN+11, "%s%08x, ", NC_STR, nonce_count); 291 | insert+=strlen(insert); 292 | cnonce=(unsigned int)rand(); 293 | snprintf(insert, 12+8, "cnonce=\"%x\", ", cnonce); 294 | insert+=strlen(insert); 295 | /* hopefully 100 is enough */ 296 | qop_tmp=str_alloc(100); 297 | snprintf(qop_tmp, 8+8+8, "%08x:%x:auth:", nonce_count, cnonce); 298 | } 299 | /* if no password is given we try it with empty password */ 300 | if (!password) 301 | password = EMPTY_STR; 302 | 303 | if (algo == SIPSAK_ALGO_MD5) { 304 | if (authhash) { 305 | strncpy((char*)&ha1_hex[0], authhash, SIPSAK_HASHHEXLEN_MD5); 306 | } 307 | else { 308 | MD5Init(&Md5Ctx); 309 | MD5Update(&Md5Ctx, usern, (unsigned int)strlen(usern)); 310 | MD5Update(&Md5Ctx, ":", 1); 311 | MD5Update(&Md5Ctx, realm, (unsigned int)strlen(realm)); 312 | MD5Update(&Md5Ctx, ":", 1); 313 | MD5Update(&Md5Ctx, password, (unsigned int)strlen(password)); 314 | MD5Final(&ha1[0], &Md5Ctx); 315 | cvt_hex(&ha1[0], &ha1_hex[0], SIPSAK_HASHLEN_MD5); 316 | } 317 | 318 | MD5Init(&Md5Ctx); 319 | MD5Update(&Md5Ctx, method, (unsigned int)strlen(method)); 320 | MD5Update(&Md5Ctx, ":", 1); 321 | MD5Update(&Md5Ctx, uri, (unsigned int)strlen(uri)); 322 | MD5Final(&ha2[0], &Md5Ctx); 323 | cvt_hex(&ha2[0], &ha2_hex[0], SIPSAK_HASHLEN_MD5); 324 | 325 | MD5Init(&Md5Ctx); 326 | MD5Update(&Md5Ctx, &ha1_hex, SIPSAK_HASHHEXLEN_MD5); 327 | MD5Update(&Md5Ctx, ":", 1); 328 | MD5Update(&Md5Ctx, nonce, (unsigned int)strlen(nonce)); 329 | MD5Update(&Md5Ctx, ":", 1); 330 | if (qop_auth == 1) { 331 | MD5Update(&Md5Ctx, qop_tmp, (unsigned int)strlen(qop_tmp)); 332 | } 333 | MD5Update(&Md5Ctx, &ha2_hex, SIPSAK_HASHHEXLEN_MD5); 334 | MD5Final(&resp[0], &Md5Ctx); 335 | cvt_hex(&resp[0], &resp_hex[0], SIPSAK_HASHLEN_MD5); 336 | } 337 | #ifdef HAVE_OPENSSL_SHA1 338 | else if (algo == SIPSAK_ALGO_SHA1) { 339 | if (authhash) { 340 | strncpy((char*)&ha1_hex[0], authhash, SIPSAK_HASHHEXLEN_SHA1); 341 | } 342 | else { 343 | SHA1_Init(&Sha1Ctx); 344 | SHA1_Update(&Sha1Ctx, usern, (unsigned int)strlen(usern)); 345 | SHA1_Update(&Sha1Ctx, ":", 1); 346 | SHA1_Update(&Sha1Ctx, realm, (unsigned int)strlen(realm)); 347 | SHA1_Update(&Sha1Ctx, ":", 1); 348 | SHA1_Update(&Sha1Ctx, password, (unsigned int)strlen(password)); 349 | SHA1_Final(&ha1[0], &Sha1Ctx); 350 | cvt_hex(&ha1[0], &ha1_hex[0], SIPSAK_HASHLEN_SHA1); 351 | } 352 | 353 | SHA1_Init(&Sha1Ctx); 354 | SHA1_Update(&Sha1Ctx, method, (unsigned int)strlen(method)); 355 | SHA1_Update(&Sha1Ctx, ":", 1); 356 | SHA1_Update(&Sha1Ctx, uri, (unsigned int)strlen(uri)); 357 | SHA1_Final(&ha2[0], &Sha1Ctx); 358 | cvt_hex(&ha2[0], &ha2_hex[0], SIPSAK_HASHLEN_SHA1); 359 | 360 | SHA1_Init(&Sha1Ctx); 361 | SHA1_Update(&Sha1Ctx, &ha1_hex, SIPSAK_HASHHEXLEN_SHA1); 362 | SHA1_Update(&Sha1Ctx, ":", 1); 363 | SHA1_Update(&Sha1Ctx, nonce, (unsigned int)strlen(nonce)); 364 | SHA1_Update(&Sha1Ctx, ":", 1); 365 | if (qop_auth == 1) { 366 | SHA1_Update(&Sha1Ctx, qop_tmp, (unsigned int)strlen(qop_tmp)); 367 | } 368 | SHA1_Update(&Sha1Ctx, &ha2_hex, SIPSAK_HASHHEXLEN_SHA1); 369 | SHA1_Final(&resp[0], &Sha1Ctx); 370 | cvt_hex(&resp[0], &resp_hex[0], SIPSAK_HASHLEN_SHA1); 371 | } 372 | else if (algo == SIPSAK_ALGO_SHA256) { 373 | if (authhash) { 374 | strncpy((char*)&ha1_hex[0], authhash, SIPSAK_HASHHEXLEN_SHA256); 375 | } 376 | else { 377 | SHA256_Init(&Sha256Ctx); 378 | SHA256_Update(&Sha256Ctx, usern, (unsigned int)strlen(usern)); 379 | SHA256_Update(&Sha256Ctx, ":", 1); 380 | SHA256_Update(&Sha256Ctx, realm, (unsigned int)strlen(realm)); 381 | SHA256_Update(&Sha256Ctx, ":", 1); 382 | SHA256_Update(&Sha256Ctx, password, (unsigned int)strlen(password)); 383 | SHA256_Final(&ha1[0], &Sha256Ctx); 384 | cvt_hex(&ha1[0], &ha1_hex[0], SIPSAK_HASHLEN_SHA256); 385 | } 386 | 387 | SHA256_Init(&Sha256Ctx); 388 | SHA256_Update(&Sha256Ctx, method, (unsigned int)strlen(method)); 389 | SHA256_Update(&Sha256Ctx, ":", 1); 390 | SHA256_Update(&Sha256Ctx, uri, (unsigned int)strlen(uri)); 391 | SHA256_Final(&ha2[0], &Sha256Ctx); 392 | cvt_hex(&ha2[0], &ha2_hex[0], SIPSAK_HASHLEN_SHA256); 393 | 394 | SHA256_Init(&Sha256Ctx); 395 | SHA256_Update(&Sha256Ctx, &ha1_hex, SIPSAK_HASHHEXLEN_SHA256); 396 | SHA256_Update(&Sha256Ctx, ":", 1); 397 | SHA256_Update(&Sha256Ctx, nonce, (unsigned int)strlen(nonce)); 398 | SHA256_Update(&Sha256Ctx, ":", 1); 399 | if (qop_auth == 1) { 400 | SHA256_Update(&Sha256Ctx, qop_tmp, (unsigned int)strlen(qop_tmp)); 401 | } 402 | SHA256_Update(&Sha256Ctx, &ha2_hex, SIPSAK_HASHHEXLEN_SHA256); 403 | SHA256_Final(&resp[0], &Sha256Ctx); 404 | cvt_hex(&resp[0], &resp_hex[0], SIPSAK_HASHLEN_SHA256); 405 | } 406 | #endif 407 | 408 | snprintf(insert, RESPONSE_STR_LEN+1, RESPONSE_STR); 409 | insert+=RESPONSE_STR_LEN; 410 | snprintf(insert, sizeof(resp_hex) + 8,"\"%s\"\r\n", &resp_hex[0]); 411 | insert+=strlen(insert); 412 | /* the auth header is complete, reinsert the rest of the request */ 413 | strncpy(insert, backup, strlen(backup)); 414 | } 415 | else { 416 | fprintf(stderr, "%s\nerror: couldn't find Proxy- or WWW-Authentication header" 417 | " in the 401 response above\n", authreq); 418 | exit_code(3, __PRETTY_FUNCTION__, "missing authentication header in reply"); 419 | } 420 | if (verbose>1) 421 | printf("authorizing\n"); 422 | /* hopefully we free all here */ 423 | free(backup); 424 | free(auth); 425 | free(method); 426 | free(uri); 427 | free(realm); 428 | free(nonce); 429 | if (auth_username == NULL) free(usern); 430 | if (qop_auth == 1) free(qop_tmp); 431 | } 432 | 433 | -------------------------------------------------------------------------------- /src/auth.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2002-2004 Fhg Fokus 3 | * Copyright (C) 2004-2022 Nils Ohlmeier 4 | * 5 | * This file belongs to sipsak, a free sip testing tool. 6 | * 7 | * sipsak is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * sipsak is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | 18 | #ifndef SIPSAK_AUTH_H 19 | #define SIPSAK_AUTH_H 20 | 21 | extern unsigned int nonce_count; 22 | 23 | void insert_auth(char *message, char *authreq, char *username, 24 | char *password, char *auth_username, char *authhash, 25 | int namebeg, int nameend); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/exit_code.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2002-2004 Fhg Fokus 3 | * Copyright (C) 2004-2022 Nils Ohlmeier 4 | * 5 | * This file belongs to sipsak, a free sip testing tool. 6 | * 7 | * sipsak is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * sipsak is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | 18 | #include "sipsak.h" 19 | 20 | #if HAVE_CONFIG_H 21 | # include "config.h" 22 | #endif 23 | 24 | #ifdef HAVE_STDIO_H 25 | # include 26 | #endif 27 | #ifdef HAVE_STDLIB_H 28 | # include 29 | #endif 30 | #ifdef HAVE_SYSLOG_H 31 | # include 32 | #endif 33 | 34 | #include "exit_code.h" 35 | #include "transport.h" 36 | 37 | enum exit_modes exit_mode = EM_DEFAULT; 38 | int sysl; 39 | 40 | void log_message(const char *message) { 41 | if ((sysl > 3) && (message != NULL)) { 42 | #ifdef HAVE_SYSLOG 43 | syslog(LOG_INFO, "%s", message); 44 | #endif 45 | } 46 | } 47 | 48 | void exit_code(int code, const char *function, const char *reason) 49 | { 50 | shutdown_network(); 51 | 52 | if ((sysl > 0) && (reason != NULL)) { 53 | #ifdef HAVE_SYSLOG 54 | syslog(LOG_INFO, "%s: %s", function, reason); 55 | closelog(); 56 | #endif 57 | } 58 | 59 | switch(exit_mode) { 60 | case EM_DEFAULT: 61 | if (code == 4) { 62 | exit(0); 63 | } else { 64 | exit(code); 65 | } 66 | case EM_NAGIOS: 67 | if (code == 0) { 68 | printf("SIP ok\n"); 69 | exit(0); 70 | } else if (code == 4) { 71 | printf("SIP warning\n"); 72 | exit(1); 73 | } else { 74 | printf("SIP failure\n"); 75 | exit(2); 76 | } 77 | default: 78 | fprintf(stderr, "ERROR: unknown exit code\n"); 79 | exit(1); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/exit_code.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2002-2004 Fhg Fokus 3 | * Copyright (C) 2004-2022 Nils Ohlmeier 4 | * 5 | * This file belongs to sipsak, a free sip testing tool. 6 | * 7 | * sipsak is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * sipsak is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | 18 | #ifndef SIPSAK_EXITCODE_H 19 | #define SIPSAK_EXITCODE_H 20 | 21 | enum exit_modes { EM_DEFAULT, EM_NAGIOS }; 22 | 23 | extern enum exit_modes exit_mode; 24 | 25 | extern int sysl; 26 | 27 | void log_message(const char *message); 28 | 29 | void exit_code(int code, const char *function, const char *reason); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/header_f.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2002-2004 Fhg Fokus 3 | * Copyright (C) 2004-2022 Nils Ohlmeier 4 | * 5 | * This file belongs to sipsak, a free sip testing tool. 6 | * 7 | * sipsak is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * sipsak is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | 18 | #include "sipsak.h" 19 | 20 | #include "header_f.h" 21 | #include "exit_code.h" 22 | #include "helper.h" 23 | #include "shoot.h" 24 | #include "transport.h" 25 | #include "sip_strings.h" 26 | 27 | 28 | /* add the given header(s) below the request line */ 29 | void insert_header(char *mes, char *header, int first) { 30 | char *ins, *backup; 31 | 32 | if (first) { 33 | ins = strchr(mes, '\n'); 34 | if (ins == NULL) { 35 | printf("failed to find a new line in the message\n"); 36 | exit_code(2, __PRETTY_FUNCTION__, "failed to find a new line in the message"); 37 | } 38 | ins++; 39 | } 40 | else { 41 | ins = mes; 42 | } 43 | backup = str_alloc(strlen(ins) + 1); 44 | strncpy(backup, ins, strlen(ins)); 45 | strncpy(ins, header, strlen(header)); 46 | strncpy(ins + strlen(header), backup, strlen(backup)+1); 47 | free(backup); 48 | } 49 | 50 | /* add a Via Header Field in the message. */ 51 | void add_via(char *mes, char *fqdn, int lport) 52 | { 53 | char *via_line, *via, *backup; 54 | 55 | if ((via=STRCASESTR(mes, VIA_STR)) == NULL && 56 | (via=STRCASESTR(mes, VIA_SHORT_STR)) == NULL) { 57 | /* We didn't found a Via so we insert our via 58 | direct after the first line. */ 59 | via=strchr(mes,'\n'); 60 | if(via == NULL) { 61 | fprintf(stderr, "error: failed to find a position to insert Via:\n" 62 | "'%s'\n", mes); 63 | exit_code(2, __PRETTY_FUNCTION__, "failed to find position to insert to insert Via header"); 64 | } 65 | via++; 66 | } 67 | if (*via == '\n') 68 | via++; 69 | /* build our own Via-header-line */ 70 | via_line = str_alloc(VIA_SIP_STR_LEN+TRANSPORT_STR_LEN+1+ 71 | strlen(fqdn)+15+30+1); 72 | snprintf(via_line, 73 | VIA_SIP_STR_LEN+TRANSPORT_STR_LEN+1+strlen(fqdn)+15+30, 74 | "%s%s %s:%i;branch=z9hG4bK.%08x;rport;alias\r\n", 75 | VIA_SIP_STR, transport_str, fqdn, lport, rand()); 76 | if (verbose > 2) 77 | printf("our Via-Line: %s\n", via_line); 78 | 79 | if (strlen(mes)+strlen(via_line)>= BUFSIZE){ 80 | printf("can't add our Via Header Line because file is too big\n"); 81 | exit_code(2, __PRETTY_FUNCTION__, "Via header to big for buffer"); 82 | } 83 | /* finnaly make a backup, insert our via and append the backup */ 84 | backup=str_alloc((strlen(via)+1)); 85 | strncpy(backup, via, strlen(via)); 86 | strncpy(via, via_line, strlen(via_line)); 87 | strncpy(via+strlen(via_line), backup, strlen(backup)+1); 88 | if (verbose > 2) 89 | printf("New message with Via-Line:\n%s\n", mes); 90 | free(via_line); 91 | free(backup); 92 | } 93 | 94 | /* copy the via lines from the message to the message 95 | reply for correct routing of our reply. 96 | */ 97 | void cpy_vias(char *reply, char *dest){ 98 | char *first_via, *middle_via, *last_via, *backup; 99 | 100 | /* lets see if we find any via */ 101 | if ((first_via=STRCASESTR(reply, VIA_STR))==NULL && 102 | (first_via=STRCASESTR(reply, VIA_SHORT_STR))==NULL ){ 103 | fprintf(stderr, "error: the received message doesn't contain a Via header\n"); 104 | exit_code(3, __PRETTY_FUNCTION__, "missing Via header in message"); 105 | } 106 | last_via=first_via+4; 107 | /* proceed additional via lines */ 108 | while ((middle_via=STRCASESTR(last_via, VIA_STR))!=NULL || 109 | (middle_via=STRCASESTR(last_via, VIA_SHORT_STR))!=NULL ) 110 | last_via=middle_via+4; 111 | last_via=strchr(last_via, '\n'); 112 | middle_via=strchr(dest, '\n')+1; 113 | if (middle_via == NULL) { 114 | fprintf(stderr, "error: failed to locate end of middle Via header\n"); 115 | exit_code(3, __PRETTY_FUNCTION__, "missing end of Via header in message"); 116 | } 117 | /* make a backup, insert the vias after the first line and append 118 | backup 119 | */ 120 | backup=str_alloc(strlen(middle_via)+1); 121 | strcpy(backup, middle_via); 122 | strncpy(middle_via, first_via, (size_t)(last_via-first_via+1)); 123 | strcpy(middle_via+(last_via-first_via+1), backup); 124 | free(backup); 125 | if (verbose > 2) 126 | printf("message reply with vias included:\n%s\n", dest); 127 | } 128 | 129 | void cpy_to(char *reply, char *dest) { 130 | char *src_to, *dst_to, *backup, *tmp; 131 | 132 | /* find the position where we want to insert the To */ 133 | if ((dst_to=STRCASESTR(dest, TO_STR))==NULL && 134 | (dst_to=STRCASESTR(dest, TO_SHORT_STR))==NULL) { 135 | fprintf(stderr, "error: could not find To in the destination: %s\n", dest); 136 | exit_code(2, __PRETTY_FUNCTION__, "missing To header in target buffer"); 137 | } 138 | if (*dst_to == '\n') 139 | dst_to++; 140 | /* find the To we want to copy */ 141 | if ((src_to=STRCASESTR(reply, TO_STR))==NULL && 142 | (src_to=STRCASESTR(reply, TO_SHORT_STR))==NULL) { 143 | if (verbose > 0) 144 | fprintf(stderr, "warning: could not find To in reply. " 145 | "trying with original To\n"); 146 | } 147 | else { 148 | if (*src_to == '\n') 149 | src_to++; 150 | /* both To found, so copy it */ 151 | tmp=strchr(dst_to, '\n'); 152 | tmp++; 153 | backup=str_alloc(strlen(tmp)+1); 154 | strcpy(backup, tmp); 155 | tmp=strchr(src_to, '\n'); 156 | strncpy(dst_to, src_to, (size_t)(tmp-src_to+1)); 157 | strcpy(dst_to+(tmp-src_to+1), backup); 158 | free(backup); 159 | if (verbose >2) 160 | printf("reply with copied To:\n%s\n", dest); 161 | } 162 | } 163 | 164 | /* check for the existence of a Max-Forwards header field. if its 165 | present it sets it to the given value, if not it will be inserted.*/ 166 | void set_maxforw(char *mes, int value){ 167 | char *max, *backup, *crlfi; 168 | int maxforward; 169 | 170 | if ((max=STRCASESTR(mes, MAX_FRW_STR))==NULL){ 171 | /* no max-forwards found so insert it after the first line*/ 172 | max=strchr(mes,'\n'); 173 | if (!max) { 174 | printf("failed to find newline\n"); 175 | exit_code(254, __PRETTY_FUNCTION__, "missing newline in buffer"); 176 | } 177 | max++; 178 | backup=str_alloc(strlen(max)+1); 179 | strncpy(backup, max, (size_t)(strlen(max))); 180 | if (value == -1) { 181 | maxforward = 70; // RFC3261 default 182 | } 183 | else { 184 | maxforward = value; 185 | } 186 | snprintf(max, MAX_FRW_STR_LEN+6, "%s%i\r\n", MAX_FRW_STR, maxforward); 187 | max=strchr(max,'\n'); 188 | max++; 189 | strncpy(max, backup, strlen(backup)+1); 190 | free(backup); 191 | if (verbose > 1) 192 | printf("Max-Forwards %i inserted into header\n", maxforward); 193 | if (verbose > 2) 194 | printf("New message with inserted Max-Forwards:\n%s\n", mes); 195 | } 196 | else{ 197 | /* found max-forwards => overwrite the value with maxforw*/ 198 | crlfi=strchr(max,'\n'); 199 | crlfi++; 200 | backup=str_alloc(strlen(crlfi)+1); 201 | strncpy(backup, crlfi, strlen(crlfi)); 202 | crlfi=max + MAX_FRW_STR_LEN; 203 | if (value == -1) { 204 | maxforward = str_to_int(1, crlfi); 205 | maxforward++; 206 | } 207 | else { 208 | maxforward = value; 209 | } 210 | snprintf(crlfi, 6, "%i\r\n", maxforward); 211 | crlfi=strchr(max,'\n'); 212 | crlfi++; 213 | strncpy(crlfi, backup, strlen(backup)+1); 214 | free(backup); 215 | if (verbose > 1) 216 | printf("Max-Forwards set to %i\n", maxforward); 217 | if (verbose > 2) 218 | printf("New message with changed Max-Forwards:\n%s\n", mes); 219 | } 220 | } 221 | 222 | /* replaces the uri in first line of mes with the other uri */ 223 | void uri_replace(char *mes, char *uri) 224 | { 225 | char *foo, *backup; 226 | 227 | foo=strchr(mes, '\n'); 228 | if (!foo) { 229 | printf("failed to find newline\n"); 230 | exit_code(254, __PRETTY_FUNCTION__, "missing newline in buffer"); 231 | } 232 | foo++; 233 | backup=str_alloc(strlen(foo)+1); 234 | strncpy(backup, foo, strlen(foo)); 235 | foo=STRCASESTR(mes, "sip"); 236 | strncpy(foo, uri, strlen(uri)); 237 | strncpy(foo+strlen(uri), SIP20_STR, SIP20_STR_LEN); 238 | strncpy(foo+strlen(uri)+SIP20_STR_LEN, backup, strlen(backup)+1); 239 | free(backup); 240 | if (verbose > 2) 241 | printf("Message with modified uri:\n%s\n", mes); 242 | } 243 | 244 | /* replace the Content-Length value with the given value */ 245 | void set_cl(char* mes, int contentlen) { 246 | char *cl, *cr, *backup; 247 | 248 | if ((cl=STRCASESTR(mes, CON_LEN_STR)) == NULL && 249 | (cl=STRCASESTR(mes, CON_LEN_SHORT_STR)) == NULL) { 250 | printf("missing Content-Length in message\n"); 251 | return; 252 | } 253 | if (*cl == '\n') { 254 | cl++; 255 | } 256 | cr = strchr(cl, '\n'); 257 | cr++; 258 | backup=str_alloc(strlen(cr)+1); 259 | strncpy(backup, cr, strlen(cr)); 260 | if (*cl == 'C') 261 | cr=cl + CON_LEN_STR_LEN; 262 | else 263 | cr=cl + 3; 264 | snprintf(cr, 6, "%i\r\n", contentlen); 265 | cr=strchr(cr, '\n'); 266 | cr++; 267 | strncpy(cr, backup, strlen(backup)+1); 268 | free(backup); 269 | if (verbose > 2) { 270 | printf("Content-Length set to %i\n" 271 | "New message with changed Content-Length:\n%s\n", contentlen, mes); 272 | } 273 | } 274 | 275 | /* returns the content length from the message; in case of error it 276 | * returns -1 */ 277 | int get_cl(char* mes) { 278 | char *cl; 279 | 280 | if ((cl=STRCASESTR(mes, CON_LEN_STR)) == NULL && 281 | (cl=STRCASESTR(mes, CON_LEN_SHORT_STR)) == NULL) { 282 | if (verbose > 1) 283 | printf("missing Content-Length in message\n"); 284 | return -1; 285 | } 286 | if (*cl == '\n') { 287 | cl+=3; 288 | } 289 | else { 290 | cl+=15; 291 | } 292 | return str_to_int(1, cl); 293 | } 294 | 295 | /* returns 1 if the rr_line contains the lr parameter 296 | * otherwise 0 */ 297 | int find_lr_parameter(char *rr_line) { 298 | char *eol, *lr; 299 | 300 | eol = strchr(rr_line, '\n'); 301 | lr = STRCASESTR(rr_line, ";lr"); 302 | if ((eol == NULL) || (lr == NULL) || (lr > eol)) { 303 | return 0; 304 | } 305 | else { 306 | return 1; 307 | } 308 | } 309 | 310 | /* copies the Record-Route header from src to dst. 311 | * if route is set Record-Route will be replaced by Route */ 312 | void cpy_rr(char* src, char *dst, int route) { 313 | char *rr, *cr, *cr2, *backup; 314 | int len; 315 | 316 | cr = strchr(dst, '\n'); 317 | if (cr == NULL) { 318 | fprintf(stderr, "error: failed to find newline in destination\n"); 319 | exit_code(3, __PRETTY_FUNCTION__, "missing newline in target buffer"); 320 | } 321 | cr++; 322 | rr = STRCASESTR(src, RR_STR); 323 | if (rr != NULL) { 324 | if (find_lr_parameter(rr) == 0) { 325 | fprintf(stderr, "error: strict routing is not support yet\n"); 326 | exit_code(252, __PRETTY_FUNCTION__, "strict routing is not supported"); 327 | } 328 | backup=str_alloc(strlen(cr)+1); 329 | strncpy(backup, cr, strlen(cr)); 330 | if (route == 0) 331 | len = RR_STR_LEN; 332 | else 333 | len = ROUTE_STR_LEN; 334 | while (rr != NULL) { 335 | if (route == 0) { 336 | strncpy(cr, RR_STR, RR_STR_LEN); 337 | } 338 | else { 339 | strncpy(cr, ROUTE_STR, ROUTE_STR_LEN); 340 | } 341 | cr += len; 342 | cr2 = strchr(rr, '\n'); 343 | if (cr2 == NULL) { 344 | fprintf(stderr, "error: failed to find end of line\n"); 345 | exit_code(3, __PRETTY_FUNCTION__, "missing newline in buffer"); 346 | } 347 | strncpy(cr, rr + RR_STR_LEN, (cr2 - (rr + len) + 1)); 348 | cr+=(cr2 - (rr + RR_STR_LEN) + 1); 349 | rr = STRCASESTR(++rr, RR_STR); 350 | } 351 | strncpy(cr, backup, strlen(backup)+1); 352 | free(backup); 353 | if (verbose > 2) 354 | printf("New message with inserted Route:\n%s\n", dst); 355 | } 356 | } 357 | 358 | /* build an ACK from the given invite and reply. 359 | * NOTE: space has to be allocated already for the ACK */ 360 | void build_ack(char *invite, char *reply, char *dest, 361 | struct sipsak_regexp *reg) { 362 | char *tmp; 363 | int len; 364 | 365 | if ((tmp = STRCASESTR(invite, "\r\n\r\n")) != NULL) { 366 | len = (tmp + 4) - invite; 367 | } 368 | else { 369 | len = strlen(invite); 370 | } 371 | memcpy(dest, invite, len); 372 | *(dest + len) = '\0'; 373 | replace_string(dest, "INVITE", "ACK"); 374 | set_cl(dest, 0); 375 | cpy_to(reply, dest); 376 | if (regexec(&(reg->okexp), reply, 0, 0, 0)==0) { 377 | cpy_rr(reply, dest, 1); 378 | /* 200 ACK must be in new transaction */ 379 | new_branch(dest); 380 | if((tmp = uri_from_contact(reply))!= NULL) { 381 | uri_replace(dest, tmp); 382 | free(tmp); 383 | } 384 | } 385 | } 386 | 387 | /* tryes to find the warning header filed and prints out the IP */ 388 | void warning_extract(char *message) 389 | { 390 | char *warning, *end, *mid, *server; 391 | int srvsize; 392 | 393 | if ((warning=STRCASESTR(message, "Warning:"))==NULL) { 394 | if (verbose > 0) 395 | printf("'no Warning header found' "); 396 | else 397 | printf("?? "); 398 | return; 399 | } 400 | end=strchr(warning, '"'); 401 | end--; 402 | warning=strchr(warning, '3'); 403 | warning+=4; 404 | mid=strchr(warning, ':'); 405 | if (mid) 406 | end=mid; 407 | srvsize=end - warning + 1; 408 | server=str_alloc((size_t)srvsize); 409 | server=strncpy(server, warning, (size_t)(srvsize - 1)); 410 | printf("%s ", server); 411 | free(server); 412 | } 413 | 414 | /* tries to find and return the number in the CSeq header */ 415 | int get_cseq(char *message) 416 | { 417 | char *cseq; 418 | int num; 419 | 420 | cseq=STRCASESTR(message, CSEQ_STR); 421 | if (cseq) { 422 | cseq+=CSEQ_STR_LEN; 423 | num=str_to_int(1, cseq); 424 | if (num < 1) { 425 | if (verbose > 2) 426 | printf("CSeq found but not convertible\n"); 427 | return 0; 428 | } 429 | return num; 430 | } 431 | if (verbose > 2) 432 | printf("no CSeq found\n"); 433 | return 0; 434 | } 435 | 436 | /* if it find the Cseq number in the message it will increased by one */ 437 | int increase_cseq(char *message, char *reply) 438 | { 439 | int cs = 0; 440 | char *cs_s, *eol, *backup; 441 | 442 | cs = get_cseq(message); 443 | if ((cs < 1) && (verbose > 1)) { 444 | printf("CSeq increase failed because unable to extract CSeq number\n"); 445 | return 0; 446 | } 447 | if (cs == INT_MAX) 448 | cs = 1; 449 | else 450 | cs++; 451 | cs_s=STRCASESTR(message, CSEQ_STR); 452 | if (cs_s) { 453 | cs_s+=6; 454 | eol=strchr(cs_s, ' '); 455 | eol++; 456 | backup=str_alloc(strlen(eol)+1); 457 | strncpy(backup, eol, (size_t)(strlen(eol))); 458 | snprintf(cs_s, 11, "%i ", cs); 459 | cs_s+=strlen(cs_s); 460 | strncpy(cs_s, backup, strlen(backup)); 461 | free(backup); 462 | } 463 | else if (verbose > 1) 464 | printf("'CSeq' not found in message\n"); 465 | if (reply != NULL) { 466 | cs_s=STRCASESTR(reply, CSEQ_STR); 467 | if (cs_s) { 468 | cs_s+=6; 469 | eol=strchr(cs_s, ' '); 470 | eol++; 471 | backup=str_alloc(strlen(eol)+1); 472 | strncpy(backup, eol, (size_t)(strlen(eol))); 473 | snprintf(cs_s, 11, "%i ", cs); 474 | cs_s+=strlen(cs_s); 475 | strncpy(cs_s, backup, strlen(backup)); 476 | free(backup); 477 | } 478 | else if (verbose > 1) 479 | printf("'CSeq' not found in reply\n"); 480 | } 481 | return cs; 482 | } 483 | 484 | /* separates the given URI into the parts by setting the pointer but it 485 | destroyes the URI */ 486 | void parse_uri(char *uri, char **scheme, char **user, char **host, int *port) 487 | { 488 | char *col, *col2, *at; 489 | col = col2 = at = NULL; 490 | *port = 0; 491 | *scheme = *user = *host = NULL; 492 | if ((col=strchr(uri,':'))!=NULL) { 493 | if ((at=strchr(uri,'@'))!=NULL) { 494 | *col = '\0'; 495 | *at = '\0'; 496 | if (at > col) { 497 | *scheme = uri; 498 | *user = ++col; 499 | *host = ++at; 500 | if ((col2=strchr(*host,':'))!=NULL) { 501 | *col2 = '\0'; 502 | *port = str_to_int(1, ++col2); 503 | } 504 | } 505 | else { 506 | *user = uri; 507 | *host = ++at; 508 | *port = str_to_int(1, ++col); 509 | } 510 | } 511 | else { 512 | *col = '\0'; 513 | col++; 514 | if ((col2=strchr(col,':'))!=NULL) { 515 | *col2 = '\0'; 516 | *scheme = uri; 517 | *host = col; 518 | *port = str_to_int(1, ++col2); 519 | } 520 | else { 521 | if (is_number(col)) { 522 | *host = uri; 523 | *port = str_to_int(1, col); 524 | } 525 | else { 526 | *scheme = uri; 527 | *host = col; 528 | } 529 | } 530 | } 531 | } 532 | else { 533 | *host = uri; 534 | } 535 | } 536 | 537 | /* return a copy of the URI from the Contact of the message if found */ 538 | char* uri_from_contact(char *message) 539 | { 540 | char *contact, *end, *tmp, c; 541 | 542 | /* try to find the contact in the redirect */ 543 | if ((contact=STRCASESTR(message, CONT_STR))==NULL && 544 | (contact=STRCASESTR(message, CONT_SHORT_STR))==NULL ) { 545 | if(verbose > 1) 546 | printf("'Contact' not found in the message\n"); 547 | return NULL; 548 | } 549 | if (*contact == '\n') 550 | contact++; 551 | 552 | if((end=strchr(contact,'\r'))!=NULL) { 553 | c = '\r'; 554 | *end = '\0'; 555 | } 556 | else if((end=strchr(contact,'\n'))!=NULL) { 557 | c = '\n'; 558 | *end = '\0'; 559 | } 560 | else { 561 | c = '\0'; 562 | end = contact + strlen(contact); 563 | } 564 | 565 | tmp = NULL; 566 | 567 | if ((contact=STRCASESTR(contact, "sip:"))!=NULL) { 568 | if ((tmp=strchr(contact+4, ';'))!=NULL) { 569 | *end = c; 570 | end = tmp; 571 | c = *end; 572 | *end = '\0'; 573 | } 574 | if ((tmp=strchr(contact+4, '>'))!=NULL) { 575 | *end = c; 576 | end = tmp; 577 | c = *end; 578 | *end = '\0'; 579 | } 580 | tmp = str_alloc(strlen(contact)+1); 581 | memcpy(tmp,contact,strlen(contact)); 582 | } 583 | 584 | *end = c; 585 | 586 | return tmp; 587 | } 588 | 589 | /* replace the 8 bytes behind the first magic cookie with a new 590 | * random value */ 591 | void new_branch(char *message) 592 | { 593 | char *branch; 594 | char backup; 595 | 596 | if((branch = STRCASESTR(message,"branch=z9hG4bK.")) != NULL) { 597 | backup = *(branch+15+8); 598 | snprintf(branch+15, 9, "%08x", rand()); 599 | *(branch+15+8) = backup; 600 | } 601 | } 602 | 603 | /* increase the CSeq and insert a new branch value */ 604 | int new_transaction(char *message, char *reply) 605 | { 606 | new_branch(message); 607 | return increase_cseq(message, reply); 608 | } 609 | 610 | /* just print the first line of the message */ 611 | void print_message_line(char *message) 612 | { 613 | char *crlf; 614 | 615 | crlf=strchr(message, '\n'); 616 | if (!crlf) { 617 | printf("failed to find newline\n"); 618 | exit_code(254, __PRETTY_FUNCTION__, "missing newline in buffer"); 619 | } 620 | else if (*(crlf - 1) == '\r') 621 | crlf--; 622 | printf("%.*s\n", (int)(crlf - message), message); 623 | } 624 | 625 | /* return pointer to the beginning of the message body */ 626 | char* get_body(char *mes) { 627 | char *cr; 628 | 629 | if ((cr = strstr(mes, "\r\n\r\n")) != NULL) { 630 | cr+=4; 631 | } 632 | return cr; 633 | } 634 | -------------------------------------------------------------------------------- /src/header_f.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2002-2004 Fhg Fokus 3 | * Copyright (C) 2004-2022 Nils Ohlmeier 4 | * 5 | * This file belongs to sipsak, a free sip testing tool. 6 | * 7 | * sipsak is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * sipsak is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | 18 | #ifndef SIPSAK_HEADER_H 19 | #define SIPSAK_HEADER_H 20 | 21 | #include "shoot.h" 22 | 23 | void insert_header(char *mes, char *header, int first); 24 | 25 | void add_via(char *mes, char *fqdn, int lport); 26 | 27 | void cpy_vias(char *reply, char *dest); 28 | 29 | void cpy_to(char *reply, char *dest); 30 | 31 | void set_maxforw(char *mes, int value); 32 | 33 | void uri_replace(char *mes, char *uri); 34 | 35 | void set_cl(char* mes, int contentlen); 36 | 37 | int get_cl(char* mes); 38 | 39 | int find_lr_parameter(char *rr_line); 40 | 41 | void cpy_rr(char* src, char *dst, int route); 42 | 43 | void build_ack(char *invite, char *reply, char *dest, 44 | struct sipsak_regexp *reg); 45 | 46 | void warning_extract(char *message); 47 | 48 | int get_cseq(char *message); 49 | 50 | int increase_cseq(char *message, char *reply); 51 | 52 | void parse_uri(char *uri, char **scheme, char **user, char **host, int *port); 53 | 54 | char* uri_from_contact(char *message); 55 | 56 | void new_branch(char *message); 57 | 58 | int new_transaction(char *message, char *reply); 59 | 60 | void print_message_line(char *message); 61 | 62 | char* get_body(char *mes); 63 | #endif 64 | -------------------------------------------------------------------------------- /src/helper.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2002-2004 Fhg Fokus 3 | * Copyright (C) 2004-2022 Nils Ohlmeier 4 | * 5 | * This file belongs to sipsak, a free sip testing tool. 6 | * 7 | * sipsak is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * sipsak is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | #include "sipsak.h" 18 | 19 | #ifdef HAVE_STDARG_H 20 | # include 21 | #endif 22 | #ifdef HAVE_NETDB_H 23 | # include 24 | #endif 25 | #ifdef HAVE_UNISTD_H 26 | # ifdef HAVE_SYS_TYPES_H 27 | # include 28 | # endif 29 | # include 30 | #endif 31 | #ifdef HAVE_SYS_UTSNAME_H 32 | # include 33 | #endif 34 | #ifdef HAVE_CTYPE_H 35 | # include 36 | #endif 37 | #ifdef HAVE_ARPA_INET_H 38 | # include 39 | #endif 40 | #ifdef HAVE_NETINET_IN_H 41 | # include 42 | #endif 43 | #ifdef HAVE_ERRNO_H 44 | # include 45 | #endif 46 | #ifdef HAVE_CARES_H 47 | # ifdef HAVE_ARPA_NAMESER_H 48 | # include 49 | # endif 50 | # include 51 | # ifndef NS_RRFIXEDSZ 52 | # define NS_RRFIXEDSZ 10 53 | # define NS_QFIXEDSZ 4 54 | # define NS_HFIXEDSZ 12 55 | # endif 56 | int caport; 57 | unsigned long caadr; 58 | int capriority; 59 | char *ca_tmpname; 60 | ares_channel channel; 61 | 62 | #endif // HAVE_CARES_H 63 | 64 | #include "helper.h" 65 | #include "exit_code.h" 66 | 67 | #if defined(RUNNING_CHECK) && !defined(HAVE_CHECK_H) 68 | #error Missing check unit test framework! 69 | #endif 70 | 71 | /* returns 1 if the string is an IP address, otherwise zero */ 72 | int is_ip(char *str) { 73 | int octet = 0; 74 | 75 | while (*str) { 76 | int digits = 0, value = 0; 77 | while (isdigit(*str) && digits <= 3) { 78 | value = (value * 10) + (*str - '0'); 79 | digits++; 80 | str++; 81 | } 82 | if (digits < 1 || digits > 3 || value > 255) 83 | return 0; 84 | octet++; 85 | if (*str != '.') 86 | break; 87 | str++; 88 | } 89 | 90 | return (*str == '\0' && octet == 4) ? 1 : 0; 91 | } 92 | 93 | /* take either a dot.decimal string of ip address or a 94 | domain name and returns a NETWORK ordered long int containing 95 | the address. i chose to internally represent the address as long for speedier 96 | comparisons. 97 | 98 | any changes to getaddress have to be patched back to the net library. 99 | contact: farhan@hotfoon.com 100 | 101 | returns zero if there is an error. 102 | this is convenient as 0 means 'this' host and the traffic of 103 | a badly behaving dns system remains inside (you send to 0.0.0.0) 104 | */ 105 | 106 | unsigned long getaddress(char *host) { 107 | struct hostent* pent; 108 | long addr; 109 | 110 | if (strlen(host) == 0) { 111 | return 0; 112 | } 113 | if (is_ip(host)) { 114 | return inet_addr(host); 115 | } 116 | 117 | /* try the system's own resolution mechanism for dns lookup: 118 | required only for domain names. 119 | in spite of what the rfc2543 :D Using SRV DNS Records recommends, 120 | we are leaving it to the operating system to do the name caching. 121 | 122 | this is an important implementational issue especially in the light 123 | dynamic dns servers like dynip.com or dyndns.com where a dial 124 | ip address is dynamically assigned a sub domain like farhan.dynip.com 125 | 126 | although expensive, this is a must to allow OS to take 127 | the decision to expire the DNS records as it deems fit. 128 | */ 129 | pent = gethostbyname(host); 130 | if (!pent) { 131 | printf("'%s' is unresolvable\n", host); 132 | exit_code(2, __PRETTY_FUNCTION__, "hostname is not resolvable"); 133 | } 134 | addr = *(uint32_t *) (pent->h_addr); 135 | return addr; 136 | } 137 | 138 | #ifdef HAVE_CARES_H 139 | static const unsigned char *parse_rr(const unsigned char *aptr, const unsigned char *abuf, int alen) { 140 | char *name; 141 | long len; 142 | int status, type, dnsclass, dlen; 143 | struct in_addr addr; 144 | 145 | if (aptr == NULL) { 146 | return NULL; 147 | } 148 | dbg("ca_tmpname: %s\n", ca_tmpname); 149 | status = ares_expand_name(aptr, abuf, alen, &name, &len); 150 | if (status != ARES_SUCCESS) { 151 | printf("error: failed to expand query name\n"); 152 | exit_code(2, __PRETTY_FUNCTION__, "failed to expand query name"); 153 | } 154 | aptr += len; 155 | if (aptr + NS_RRFIXEDSZ > abuf + alen) { 156 | printf("error: not enough data in DNS answer 1\n"); 157 | free(name); 158 | return NULL; 159 | } 160 | type = DNS_RR_TYPE(aptr); 161 | dnsclass = DNS_RR_CLASS(aptr); 162 | dlen = DNS_RR_LEN(aptr); 163 | aptr += NS_RRFIXEDSZ; 164 | if (aptr + dlen > abuf + alen) { 165 | printf("error: not enough data in DNS answer 2\n"); 166 | free(name); 167 | return NULL; 168 | } 169 | if (dnsclass != CARES_CLASS_C_IN) { 170 | printf("error: unsupported dnsclass (%i) in DNS answer\n", dnsclass); 171 | free(name); 172 | return NULL; 173 | } 174 | if (type != CARES_TYPE_SRV && type != CARES_TYPE_A && type != CARES_TYPE_CNAME) { 175 | printf("error: unsupported DNS response type (%i)\n", type); 176 | free(name); 177 | return NULL; 178 | } 179 | if (type == CARES_TYPE_SRV) { 180 | free(name); 181 | int priority = DNS__16BIT(aptr); 182 | dbg("Processing SRV record with priority %d\n", priority); 183 | if (capriority == -1 || priority < capriority) { 184 | capriority = priority; 185 | caport = DNS__16BIT(aptr + 4); 186 | dbg("caport: %i\n", caport); 187 | status = ares_expand_name(aptr + 6, abuf, alen, &name, &len); 188 | if (status != ARES_SUCCESS) { 189 | printf("error: failed to expand SRV name\n"); 190 | return NULL; 191 | } 192 | dbg("SRV name: %s\n", name); 193 | if (is_ip(name)) { 194 | caadr = inet_addr(name); 195 | free(name); 196 | } 197 | else { 198 | if (ca_tmpname) { 199 | free(ca_tmpname); 200 | } 201 | ca_tmpname = name; 202 | } 203 | } 204 | } 205 | else if (type == CARES_TYPE_CNAME) { 206 | if ((ca_tmpname != NULL) && 207 | (STRNCASECMP(ca_tmpname, name, strlen(ca_tmpname)) == 0)) { 208 | if (ca_tmpname) { 209 | free(ca_tmpname); 210 | } 211 | ca_tmpname = malloc(strlen(name) + 1); 212 | if (ca_tmpname == NULL) { 213 | printf("error: failed to allocate memory\n"); 214 | exit_code(2, __PRETTY_FUNCTION__, "memory allocation failure"); 215 | } 216 | strcpy(ca_tmpname, name); 217 | free(name); 218 | } 219 | else { 220 | free(name); 221 | status = ares_expand_name(aptr, abuf, alen, &name, &len); 222 | if (status != ARES_SUCCESS) { 223 | printf("error: failed to expand CNAME\n"); 224 | return NULL; 225 | } 226 | dbg("CNAME: %s\n", name); 227 | if (is_ip(name)) { 228 | caadr = inet_addr(name); 229 | free(name); 230 | } 231 | else { 232 | if (ca_tmpname) { 233 | free(ca_tmpname); 234 | } 235 | ca_tmpname = name; 236 | } 237 | } 238 | } 239 | else if (type == CARES_TYPE_A) { 240 | if (dlen == 4 && STRNCASECMP(ca_tmpname, name, strlen(ca_tmpname)) == 0) { 241 | memcpy(&addr, aptr, sizeof(struct in_addr)); 242 | caadr = addr.s_addr; 243 | } 244 | free(name); 245 | } 246 | return aptr + dlen; 247 | } 248 | 249 | static const unsigned char *skip_rr(const unsigned char *aptr, const unsigned char *abuf, int alen) { 250 | int status, dlen; 251 | long len; 252 | char *name; 253 | 254 | if (aptr == NULL) { 255 | return NULL; 256 | } 257 | dbg("skipping rr section...\n"); 258 | status = ares_expand_name(aptr, abuf, alen, &name, &len); 259 | if (status != ARES_SUCCESS) { 260 | return NULL; 261 | } 262 | aptr += len; 263 | dlen = DNS_RR_LEN(aptr); 264 | aptr += NS_RRFIXEDSZ; 265 | aptr += dlen; 266 | free(name); 267 | return aptr; 268 | } 269 | 270 | static const unsigned char *skip_query(const unsigned char *aptr, const unsigned char *abuf, int alen) { 271 | int status; 272 | long len; 273 | char *name; 274 | 275 | if (aptr == NULL) { 276 | return NULL; 277 | } 278 | dbg("skipping query section...\n"); 279 | status = ares_expand_name(aptr, abuf, alen, &name, &len); 280 | if (status != ARES_SUCCESS) { 281 | return NULL; 282 | } 283 | aptr += len; 284 | aptr += NS_QFIXEDSZ; 285 | free(name); 286 | return aptr; 287 | } 288 | 289 | static void cares_callback(void *arg, int status, int timeouts, unsigned char *abuf, int alen) { 290 | int i; 291 | unsigned int ancount, nscount, arcount; 292 | const unsigned char *aptr; 293 | 294 | dbg("cares_callback: status=%i, alen=%i\n", status, alen); 295 | if (status != ARES_SUCCESS) { 296 | if (verbose > 1) 297 | printf("ares failed: %s\n", ares_strerror(status)); 298 | return; 299 | } 300 | 301 | ancount = DNS_HEADER_ANCOUNT(abuf); 302 | nscount = DNS_HEADER_NSCOUNT(abuf); 303 | arcount = DNS_HEADER_ARCOUNT(abuf); 304 | 305 | dbg("ancount: %i, nscount: %i, arcount: %i\n", ancount, nscount, arcount); 306 | 307 | /* safety check */ 308 | if (alen < NS_HFIXEDSZ) 309 | return; 310 | aptr = abuf + NS_HFIXEDSZ; 311 | 312 | aptr = skip_query(aptr, abuf, alen); 313 | if (aptr == NULL) { 314 | return; 315 | } 316 | 317 | for (i = 0; i < ancount && aptr != NULL; i++) { 318 | aptr = parse_rr(aptr, abuf, alen); 319 | } 320 | if (caadr == 0 && aptr != NULL) { 321 | for (i = 0; i < nscount && aptr != NULL; i++) { 322 | aptr = skip_rr(aptr, abuf, alen); 323 | } 324 | for (i = 0; i < arcount && aptr != NULL; i++) { 325 | aptr = parse_rr(aptr, abuf, alen); 326 | } 327 | } 328 | } 329 | 330 | static inline unsigned long srv_ares(char *host, int *port, char *srv) { 331 | int nfds, count, srvh_len; 332 | char *srvh; 333 | fd_set read_fds, write_fds; 334 | struct timeval *tvp, tv; 335 | 336 | caport = 0; 337 | caadr = 0; 338 | capriority = -1; 339 | ca_tmpname = NULL; 340 | dbg("starting ARES query\n"); 341 | 342 | srvh_len = strlen(host) + strlen(srv) + 2; 343 | srvh = malloc(srvh_len); 344 | if (srvh == NULL) { 345 | printf("error: failed to allocate memory (%i) for ares query\n", srvh_len); 346 | exit_code(2, __PRETTY_FUNCTION__, "memory allocation failure"); 347 | } 348 | memset(srvh, 0, srvh_len); 349 | strncpy(srvh, srv, strlen(srv)); 350 | memcpy(srvh + strlen(srv), ".", 1); 351 | strcpy(srvh + strlen(srv) + 1, host); 352 | dbg("hostname: '%s', len: %i\n", srvh, srvh_len); 353 | 354 | ares_query(channel, srvh, CARES_CLASS_C_IN, CARES_TYPE_SRV, cares_callback, (char *) NULL); 355 | dbg("ares_query finished, waiting for result...\n"); 356 | /* wait for query to complete */ 357 | while (1) { 358 | FD_ZERO(&read_fds); 359 | FD_ZERO(&write_fds); 360 | nfds = ares_fds(channel, &read_fds, &write_fds); 361 | if (nfds == 0) 362 | break; 363 | tvp = ares_timeout(channel, NULL, &tv); 364 | count = select(nfds, &read_fds, &write_fds, NULL, tvp); 365 | if (count < 0 && errno != EINVAL) { 366 | perror("ares select"); 367 | exit_code(2, __PRETTY_FUNCTION__, "ares DNS resolution failure"); 368 | } 369 | ares_process(channel, &read_fds, &write_fds); 370 | } 371 | dbg("ARES answer processed\n"); 372 | *port = caport; 373 | if (caadr == 0 && ca_tmpname != NULL) { 374 | caadr = getaddress(ca_tmpname); 375 | } 376 | if (ca_tmpname != NULL) 377 | free(ca_tmpname); 378 | free(srvh); 379 | return caadr; 380 | } 381 | #endif // HAVE_CARES_H 382 | 383 | unsigned long getsrvaddress(char *host, int *port, char *srv) { 384 | #ifdef HAVE_CARES_H 385 | return srv_ares(host, port, srv); 386 | #else // HAVE_CARES_H 387 | return 0; 388 | #endif 389 | } 390 | 391 | /* Finds the SRV records for the given host. It returns the target IP 392 | * address and fills the port and transport if a suitable SRV record 393 | * exists. Otherwise it returns 0. The function follows 3263: first 394 | * TLS, then TCP and finally UDP. */ 395 | unsigned long getsrvadr(char *host, int *port, unsigned int *transport) { 396 | unsigned long adr = 0; 397 | 398 | #ifdef HAVE_SRV 399 | int srvport = 5060; 400 | 401 | #ifdef HAVE_CARES_H 402 | int status; 403 | int optmask = ARES_OPT_FLAGS; 404 | struct ares_options options; 405 | 406 | options.flags = ARES_FLAG_NOCHECKRESP; 407 | options.servers = NULL; 408 | options.nservers = 0; 409 | 410 | status = ares_init_options(&channel, &options, optmask); 411 | if (status != ARES_SUCCESS) { 412 | printf("error: failed to initialize ares\n"); 413 | exit_code(2, __PRETTY_FUNCTION__, "failed to init ares lib"); 414 | } 415 | #endif 416 | 417 | #ifdef WITH_TLS_TRANSP 418 | adr = getsrvaddress(host, &srvport, SRV_SIP_TLS); 419 | if (adr != 0) { 420 | *transport = SIP_TLS_TRANSPORT; 421 | if (verbose > 1) 422 | printf("using SRV record: %s.%s:%i\n", SRV_SIP_TLS, host, srvport); 423 | } 424 | else { 425 | #endif 426 | adr = getsrvaddress(host, &srvport, SRV_SIP_TCP); 427 | if (adr != 0) { 428 | *transport = SIP_TCP_TRANSPORT; 429 | if (verbose > 1) 430 | printf("using SRV record: %s.%s:%i\n", SRV_SIP_TCP, host, srvport); 431 | } 432 | else { 433 | adr = getsrvaddress(host, &srvport, SRV_SIP_UDP); 434 | if (adr != 0) { 435 | *transport = SIP_UDP_TRANSPORT; 436 | if (verbose > 1) 437 | printf("using SRV record: %s.%s:%i\n", SRV_SIP_UDP, host, srvport); 438 | } 439 | } 440 | #ifdef WITH_TLS_TRANSP 441 | } 442 | #endif 443 | 444 | #ifdef HAVE_CARES_H 445 | ares_destroy(channel); 446 | #endif 447 | 448 | *port = srvport; 449 | #endif // HAVE_SRV 450 | return adr; 451 | } 452 | 453 | /* because the full qualified domain name is needed by many other 454 | functions it will be determined by this function. 455 | */ 456 | void get_fqdn(char *buf, int numeric, char *hostname) { 457 | char hname[100], dname[100], hlp[18]; 458 | size_t namelen=100; 459 | struct hostent* he; 460 | struct utsname un; 461 | 462 | memset(&hname, 0, sizeof(hname)); 463 | memset(&dname, 0, sizeof(dname)); 464 | memset(&hlp, 0, sizeof(hlp)); 465 | 466 | if (hostname) { 467 | strncpy(buf, hostname, FQDN_SIZE-1); 468 | strncpy(hname, hostname, sizeof(hname)-1); 469 | } 470 | else { 471 | if ((uname(&un))==0) { 472 | strncpy(hname, un.nodename, sizeof(hname)-1); 473 | } 474 | else { 475 | if (gethostname(&hname[0], namelen) < 0) { 476 | fprintf(stderr, "error: cannot determine hostname\n"); 477 | exit_code(2, __PRETTY_FUNCTION__, "failed to determine hostname"); 478 | } 479 | } 480 | #ifdef HAVE_GETDOMAINNAME 481 | /* a hostname with dots should be a domainname */ 482 | if ((strchr(hname, '.'))==NULL) { 483 | if (getdomainname(&dname[0], namelen) < 0) { 484 | fprintf(stderr, "error: cannot determine domainname\n"); 485 | exit_code(2, __PRETTY_FUNCTION__, "failed to get domainname"); 486 | } 487 | if (strcmp(&dname[0],"(none)")!=0) 488 | snprintf(buf, FQDN_SIZE, "%s.%s", hname, dname); 489 | } 490 | else { 491 | strncpy(buf, hname, FQDN_SIZE-1); 492 | } 493 | #endif 494 | } 495 | 496 | if (!(numeric == 1 && is_ip(buf))) { 497 | he=gethostbyname(hname); 498 | if (he) { 499 | if (numeric == 1) { 500 | snprintf(hlp, sizeof(hlp), "%s", inet_ntoa(*(struct in_addr *) he->h_addr_list[0])); 501 | strncpy(buf, hlp, FQDN_SIZE-1); 502 | } 503 | else { 504 | if ((strchr(he->h_name, '.'))!=NULL && (strchr(hname, '.'))==NULL) { 505 | strncpy(buf, he->h_name, FQDN_SIZE-1); 506 | } 507 | else { 508 | strncpy(buf, hname, FQDN_SIZE-1); 509 | } 510 | } 511 | } 512 | else { 513 | fprintf(stderr, "error: cannot resolve local hostname: %s\n", hname); 514 | exit_code(2, __PRETTY_FUNCTION__, "failed to resolve local hostname"); 515 | } 516 | } 517 | if ((strchr(buf, '.'))==NULL) { 518 | if (hostname) { 519 | fprintf(stderr, "warning: %s is not resolvable... continuing anyway\n", buf); 520 | strncpy(buf, hostname, FQDN_SIZE-1); 521 | } 522 | else { 523 | fprintf(stderr, "error: this FQDN or IP is not valid: %s\n", buf); 524 | exit_code(2, __PRETTY_FUNCTION__, "invalid IP or FQDN"); 525 | } 526 | } 527 | 528 | if (verbose > 2) 529 | printf("fqdnhostname: %s\n", buf); 530 | } 531 | 532 | /* this function searches for search in mess and replaces it with 533 | replacement */ 534 | void replace_string(char *mess, char *search, char *replacement) { 535 | char *backup, *insert; 536 | 537 | insert=STRCASESTR(mess, search); 538 | if (insert==NULL){ 539 | if (verbose > 2) 540 | fprintf(stderr, "warning: could not find this '%s' replacement string in " 541 | "message\n", search); 542 | } 543 | else { 544 | while (insert){ 545 | backup=str_alloc(strlen(insert)+1); 546 | strcpy(backup, insert+strlen(search)); 547 | strcpy(insert, replacement); 548 | strcpy(insert+strlen(replacement), backup); 549 | free(backup); 550 | insert=STRCASESTR(mess, search); 551 | } 552 | } 553 | } 554 | 555 | /* checks if the strings contains special double marks and then 556 | * replace all occurrences of this strings in the message */ 557 | void replace_strings(char *mes, char *strings) { 558 | char *pos, *atr, *val, *repl, *end; 559 | char sep; 560 | 561 | pos=atr=val=repl = NULL; 562 | dbg("replace_strings entered\nstrings: '%s'\n", strings); 563 | if ((isalnum(*strings) != 0) && 564 | (isalnum(*(strings + strlen(strings) - 1)) != 0)) { 565 | replace_string(mes, "$replace$", strings); 566 | } 567 | else { 568 | sep = *strings; 569 | dbg("sep: '%c'\n", sep); 570 | end = strings + strlen(strings); 571 | pos = strings + 1; 572 | while (pos < end) { 573 | atr = pos; 574 | pos = strchr(atr, sep); 575 | if (pos != NULL) { 576 | *pos = '\0'; 577 | val = pos + 1; 578 | pos = strchr(val, sep); 579 | if (pos != NULL) { 580 | *pos = '\0'; 581 | pos++; 582 | } 583 | } 584 | dbg("atr: '%s'\nval: '%s'\n", atr, val); 585 | if ((atr != NULL) && (val != NULL)) { 586 | repl = str_alloc(strlen(val) + 3); 587 | if (repl == NULL) { 588 | printf("failed to allocate memory\n"); 589 | exit_code(2, __PRETTY_FUNCTION__, "memory allocation failure"); 590 | } 591 | sprintf(repl, "$%s$", atr); 592 | replace_string(mes, repl, val); 593 | free(repl); 594 | } 595 | dbg("pos: '%s'\n", pos); 596 | } 597 | } 598 | dbg("mes:\n'%s'\n", mes); 599 | } 600 | 601 | /* insert \r in front of all \n if it is not present already 602 | * and and a trailing \r\n is not present */ 603 | void insert_cr(char *mes) { 604 | char *lf, *pos, *backup; 605 | 606 | pos = mes; 607 | lf = strchr(pos, '\n'); 608 | while ((lf != NULL) && (lf >= mes+1) && (*(--lf) != '\r')) { 609 | backup=str_alloc(strlen(lf)+2); 610 | strcpy(backup, lf+1); 611 | *(lf+1) = '\r'; 612 | strcpy(lf+2, backup); 613 | free(backup); 614 | pos = lf+3; 615 | lf = strchr(pos, '\n'); 616 | } 617 | lf = STRCASESTR(mes, "\r\n\r\n"); 618 | if (lf == NULL) { 619 | lf = mes + strlen(mes); 620 | sprintf(lf, "\r\n"); 621 | } 622 | } 623 | 624 | /* sipmly swappes the content of the two buffers */ 625 | void swap_buffers(char *fst, char *snd) { 626 | char *tmp; 627 | 628 | if (fst == snd) 629 | return; 630 | tmp = str_alloc(strlen(fst)+1); 631 | strcpy(tmp, fst); 632 | strcpy(fst, snd); 633 | strcpy(snd, tmp); 634 | free(tmp); 635 | } 636 | 637 | void swap_ptr(char **fst, char **snd) { 638 | char *tmp; 639 | 640 | tmp = *fst; 641 | *fst = *snd; 642 | *snd = tmp; 643 | } 644 | 645 | /* trashes one character in buff randomly */ 646 | void trash_random(char *message) { 647 | int r; 648 | float t; 649 | char *position; 650 | 651 | t=(float)rand()/RAND_MAX; 652 | r=(int)(t * (float)strlen(message)); 653 | position=message+r; 654 | r=(int)(t*(float)255); 655 | *position=(char)r; 656 | if (verbose > 2) 657 | printf("request:\n%s\n", message); 658 | } 659 | 660 | /* this function is taken from traceroute-1.4_p12 661 | which is distributed under the GPL and it returns 662 | the difference between to timeval structs */ 663 | double deltaT(struct timeval *t1p, struct timeval *t2p) { 664 | register double dt; 665 | 666 | dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + 667 | (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; 668 | return (dt); 669 | } 670 | 671 | /* returns one if the string contains only numbers otherwise zero */ 672 | int is_number(char *number) { 673 | int digit = 1; 674 | if (strlen(number) == 0) { 675 | return 0; 676 | } 677 | while (digit && (*number != '\0')) { 678 | digit = isdigit(*number); 679 | number++; 680 | } 681 | return digit ? 1 : 0; 682 | } 683 | 684 | /* tries to convert the given string into an integer. it strips 685 | * white-spaces and exits if an error happens */ 686 | int str_to_int(int mode, char *num) { 687 | int ret, len; 688 | char *end, *start; 689 | char *backup = NULL; 690 | 691 | len = strlen(num); 692 | if (len == 0) { 693 | fprintf(stderr, "error: string has zero length: '%s'\n", num); 694 | ret = 2; 695 | goto error; 696 | } 697 | /* we need to make a backup to insert the zero char */ 698 | backup = malloc(len + 1); 699 | if (!backup) { 700 | fprintf(stderr, "error: failed to allocate memory\n"); 701 | ret = 2; 702 | goto error; 703 | } 704 | memcpy(backup, num, len + 1); 705 | 706 | start = backup; 707 | end = backup + len; 708 | while (isspace(*start) && (start < end)) { 709 | start++; 710 | } 711 | if (start == end) { 712 | fprintf(stderr, "error: string is too short: '%s'\n", num); 713 | ret = 2; 714 | goto error; 715 | } 716 | if (mode == 0) { 717 | end--; 718 | while (isspace(*end) && (end > start)) { 719 | end--; 720 | } 721 | if (end != (backup + len - 1)) { 722 | end++; 723 | *end = '\0'; 724 | } 725 | } 726 | else { 727 | end = start; 728 | end++; 729 | while ((end < backup + len) && *end != '\0' && !isspace(*end)) { 730 | end++; 731 | } 732 | *end = '\0'; 733 | } 734 | if (!is_number(start)) { 735 | fprintf(stderr, "error: string is not a number: '%s'\n", start); 736 | ret = 2; 737 | goto error; 738 | } 739 | ret = atoi(start); 740 | if (ret >= 0) { 741 | free(backup); 742 | return ret; 743 | } 744 | else { 745 | fprintf(stderr, "error: failed to convert string to integer: '%s'\n", num); 746 | ret = 2; 747 | } 748 | error: 749 | if (backup) { 750 | free(backup); 751 | } 752 | if (mode == 0) { 753 | /* libcheck expects a return value not an exit code */ 754 | #ifndef RUNNING_CHECK 755 | exit_code(ret, __PRETTY_FUNCTION__, NULL); 756 | #endif 757 | } 758 | return (ret * - 1); 759 | } 760 | 761 | /* reads into the given buffer from standard input until the EOF 762 | * character, LF character or the given size of the buffer is exceeded */ 763 | int read_stdin(char *buf, int size, int ret) { 764 | int i, j; 765 | 766 | for(i = 0; i < size - 1; i++) { 767 | j = getchar(); 768 | if (((ret == 0) && (j == EOF)) || 769 | ((ret == 1) && (j == '\n'))) { 770 | *(buf + i) = '\0'; 771 | return i; 772 | } 773 | else { 774 | *(buf + i) = j; 775 | } 776 | } 777 | *(buf + i) = '\0'; 778 | if (verbose) 779 | fprintf(stderr, "warning: readin buffer size exceeded\n"); 780 | return i; 781 | } 782 | 783 | /* tries to allocate the given size of memory and sets it all to zero. 784 | * if the allocation fails it exits */ 785 | void *str_alloc(size_t size) { 786 | char *ptr; 787 | #ifdef HAVE_CALLOC 788 | ptr = calloc(1, size); 789 | #else 790 | ptr = malloc(size); 791 | #endif 792 | if (ptr == NULL) { 793 | fprintf(stderr, "error: memory allocation for %lu bytes failed\n", size); 794 | exit_code(255, __PRETTY_FUNCTION__, "memory allocation failure"); 795 | } 796 | #ifndef HAVE_CALLOC 797 | memset(ptr, 0, size); 798 | #endif 799 | return ptr; 800 | } 801 | 802 | void dbg(char* format, ...) { 803 | #ifdef DEBUG 804 | va_list ap; 805 | 806 | fprintf(stderr, "DEBUG: "); 807 | va_start(ap, format); 808 | vfprintf(stderr, format, ap); 809 | fflush(stderr); 810 | va_end(ap); 811 | #endif 812 | } 813 | -------------------------------------------------------------------------------- /src/helper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2002-2004 Fhg Fokus 3 | * Copyright (C) 2004-2022 Nils Ohlmeier 4 | * 5 | * This file belongs to sipsak, a free sip testing tool. 6 | * 7 | * sipsak is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * sipsak is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | 18 | #ifndef SIPSAK_HELPER_H 19 | #define SIPSAK_HELPER_H 20 | 21 | #include "sipsak.h" 22 | 23 | #ifdef HAVE_SYS_TIME_H 24 | # include 25 | #else 26 | # include 27 | #endif 28 | #ifdef HAVE_SYS_SELECT_H 29 | # include 30 | #endif 31 | 32 | #ifdef HAVE_CARES_H 33 | # define HAVE_SRV 34 | #endif 35 | 36 | #ifdef HAVE_CARES_H 37 | # define CARES_TYPE_A 1 38 | # define CARES_TYPE_CNAME 5 39 | # define CARES_TYPE_SRV 33 40 | # define CARES_CLASS_C_IN 1 41 | /* copied from ares_dns.h */ 42 | # define DNS__16BIT(p) (((p)[0] << 8) | (p)[1]) 43 | # define DNS_HEADER_ANCOUNT(h) DNS__16BIT((h) + 6) 44 | # define DNS_HEADER_NSCOUNT(h) DNS__16BIT((h) + 8) 45 | # define DNS_HEADER_ARCOUNT(h) DNS__16BIT((h) + 10) 46 | # define DNS_RR_TYPE(r) DNS__16BIT(r) 47 | # define DNS_RR_CLASS(r) DNS__16BIT((r) + 2) 48 | # define DNS_RR_LEN(r) DNS__16BIT((r) + 8) 49 | #endif 50 | 51 | #ifdef HAVE_SRV 52 | # define SRV_SIP_TLS "_sip._tls" 53 | # define SRV_SIP_TCP "_sip._tcp" 54 | # define SRV_SIP_UDP "_sip._udp" 55 | #endif 56 | 57 | int is_ip(char *str); 58 | 59 | unsigned long getaddress(char *host); 60 | 61 | unsigned long getsrvadr(char *host, int *port, unsigned int *transport); 62 | 63 | void get_fqdn(char *buf, int numeric, char *hostname); 64 | 65 | void replace_string(char *mes, char *search, char *replacement); 66 | 67 | void replace_strings(char *mes, char *strings); 68 | 69 | void insert_cr(char *mes); 70 | 71 | void swap_buffers(char *fst, char *snd); 72 | 73 | void swap_ptr(char **fst, char **snd); 74 | 75 | void trash_random(char *message); 76 | 77 | double deltaT(struct timeval *t1p, struct timeval *t2p); 78 | 79 | int is_number(char *number); 80 | 81 | int str_to_int(int mode, char *num); 82 | 83 | int read_stdin(char *buf, int size, int ret); 84 | 85 | void *str_alloc(size_t size); 86 | 87 | void dbg(char* format, ...); 88 | #endif 89 | -------------------------------------------------------------------------------- /src/md5.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm 4 | 5 | Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All 6 | rights reserved. 7 | 8 | License to copy and use this software is granted provided that it 9 | is identified as the "RSA Data Security, Inc. MD5 Message-Digest 10 | Algorithm" in all material mentioning or referencing this software 11 | or this function. 12 | 13 | License is also granted to make and use derivative works provided 14 | that such works are identified as "derived from the RSA Data 15 | Security, Inc. MD5 Message-Digest Algorithm" in all material 16 | mentioning or referencing the derived work. 17 | 18 | RSA Data Security, Inc. makes no representations concerning either 19 | the merchantability of this software or the suitability of this 20 | software for any particular purpose. It is provided "as is" 21 | without express or implied warranty of any kind. 22 | 23 | These notices must be retained in any copies of any part of this 24 | documentation and/or software. 25 | */ 26 | 27 | #ifdef HAVE_CONFIG_H 28 | # include "config.h" 29 | #endif 30 | 31 | #include "md5.h" 32 | 33 | #ifndef HAVE_EXTERNAL_MD5 34 | 35 | #ifdef HAVE_STRING_H 36 | # include 37 | #endif 38 | 39 | #if defined(RUNNING_CHECK) && !defined(HAVE_CHECK_H) 40 | #error Missing check unit test framework! 41 | #endif 42 | 43 | #define USE_MEM 44 | 45 | /* Constants for MD5Transform routine. 46 | */ 47 | 48 | 49 | 50 | 51 | #define S11 7 52 | #define S12 12 53 | #define S13 17 54 | #define S14 22 55 | #define S21 5 56 | #define S22 9 57 | #define S23 14 58 | #define S24 20 59 | #define S31 4 60 | #define S32 11 61 | #define S33 16 62 | #define S34 23 63 | #define S41 6 64 | #define S42 10 65 | #define S43 15 66 | #define S44 21 67 | 68 | static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64])); 69 | static void Encode PROTO_LIST 70 | ((unsigned char *, UINT4 *, unsigned int)); 71 | static void Decode PROTO_LIST 72 | ((UINT4 *, unsigned char *, unsigned int)); 73 | static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int)); 74 | static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int)); 75 | 76 | static unsigned char PADDING[64] = { 77 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 78 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 80 | }; 81 | 82 | /* F, G, H and I are basic MD5 functions. 83 | */ 84 | #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) 85 | #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) 86 | #define H(x, y, z) ((x) ^ (y) ^ (z)) 87 | #define I(x, y, z) ((y) ^ ((x) | (~z))) 88 | 89 | /* ROTATE_LEFT rotates x left n bits. 90 | */ 91 | #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) 92 | 93 | /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. 94 | Rotation is separate from addition to prevent recomputation. 95 | */ 96 | #define FF(a, b, c, d, x, s, ac) { \ 97 | (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ 98 | (a) = ROTATE_LEFT ((a), (s)); \ 99 | (a) += (b); \ 100 | } 101 | #define GG(a, b, c, d, x, s, ac) { \ 102 | (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ 103 | (a) = ROTATE_LEFT ((a), (s)); \ 104 | (a) += (b); \ 105 | } 106 | #define HH(a, b, c, d, x, s, ac) { \ 107 | (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ 108 | (a) = ROTATE_LEFT ((a), (s)); \ 109 | (a) += (b); \ 110 | } 111 | #define II(a, b, c, d, x, s, ac) { \ 112 | (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ 113 | (a) = ROTATE_LEFT ((a), (s)); \ 114 | (a) += (b); \ 115 | } 116 | 117 | /* MD5 initialization. Begins an MD5 operation, writing a new context. 118 | */ 119 | void MD5Init (context) 120 | MD5_CTX *context; /* context */ 121 | { 122 | context->count[0] = context->count[1] = 0; 123 | /* Load magic initialization constants. 124 | */ 125 | context->state[0] = 0x67452301; 126 | context->state[1] = 0xefcdab89; 127 | context->state[2] = 0x98badcfe; 128 | context->state[3] = 0x10325476; 129 | } 130 | 131 | /* MD5 block update operation. Continues an MD5 message-digest 132 | operation, processing another message block, and updating the 133 | context. 134 | */ 135 | void MD5Update (context, input, inputLen) 136 | MD5_CTX *context; /* context */ 137 | unsigned char *input; /* input block */ 138 | unsigned int inputLen; /* length of input block */ 139 | { 140 | unsigned int i, index, partLen; 141 | 142 | /* Compute number of bytes mod 64 */ 143 | index = (unsigned int)((context->count[0] >> 3) & 0x3F); 144 | 145 | /* Update number of bits */ 146 | if ((context->count[0] += ((UINT4)inputLen << 3)) 147 | 148 | < ((UINT4)inputLen << 3)) 149 | context->count[1]++; 150 | context->count[1] += ((UINT4)inputLen >> 29); 151 | 152 | partLen = 64 - index; 153 | 154 | /* Transform as many times as possible. 155 | */ 156 | if (inputLen >= partLen) { 157 | MD5_memcpy 158 | ((POINTER)&context->buffer[index], (POINTER)input, partLen); 159 | MD5Transform (context->state, context->buffer); 160 | 161 | for (i = partLen; i + 63 < inputLen; i += 64) 162 | MD5Transform (context->state, &input[i]); 163 | 164 | index = 0; 165 | } 166 | else 167 | i = 0; 168 | 169 | /* Buffer remaining input */ 170 | MD5_memcpy 171 | ((POINTER)&context->buffer[index], (POINTER)&input[i], 172 | inputLen-i); 173 | } 174 | 175 | /* MD5 finalization. Ends an MD5 message-digest operation, writing the 176 | the message digest and zeroizing the context. 177 | */ 178 | void MD5Final (digest, context) 179 | unsigned char digest[16]; /* message digest */ 180 | MD5_CTX *context; /* context */ 181 | { 182 | unsigned char bits[8]; 183 | unsigned int index, padLen; 184 | 185 | /* Save number of bits */ 186 | Encode (bits, context->count, 8); 187 | 188 | /* Pad out to 56 mod 64. 189 | */ 190 | index = (unsigned int)((context->count[0] >> 3) & 0x3f); 191 | padLen = (index < 56) ? (56 - index) : (120 - index); 192 | MD5Update (context, PADDING, padLen); 193 | 194 | /* Append length (before padding) */ 195 | MD5Update (context, bits, 8); 196 | 197 | /* Store state in digest */ 198 | Encode (digest, context->state, 16); 199 | 200 | /* Zeroize sensitive information. 201 | */ 202 | MD5_memset ((POINTER)context, 0, sizeof (*context)); 203 | } 204 | 205 | /* MD5 basic transformation. Transforms state based on block. 206 | */ 207 | static void MD5Transform (state, block) 208 | UINT4 state[4]; 209 | unsigned char block[64]; 210 | { 211 | UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; 212 | 213 | Decode (x, block, 64); 214 | 215 | /* Round 1 */ 216 | FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ 217 | FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ 218 | FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ 219 | FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ 220 | FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ 221 | FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ 222 | FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ 223 | FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ 224 | FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ 225 | FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ 226 | FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ 227 | FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ 228 | FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ 229 | FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ 230 | FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ 231 | FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ 232 | 233 | /* Round 2 */ 234 | GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ 235 | GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ 236 | GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ 237 | GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ 238 | GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ 239 | GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ 240 | GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ 241 | GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ 242 | GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ 243 | GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ 244 | GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ 245 | GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ 246 | GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ 247 | GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ 248 | GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ 249 | GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ 250 | 251 | /* Round 3 */ 252 | HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ 253 | HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ 254 | HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ 255 | HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ 256 | HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ 257 | HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ 258 | HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ 259 | HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ 260 | HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ 261 | HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ 262 | HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ 263 | HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ 264 | HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ 265 | HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ 266 | HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ 267 | HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ 268 | 269 | /* Round 4 */ 270 | II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ 271 | II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ 272 | II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ 273 | II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ 274 | II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ 275 | II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ 276 | II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ 277 | II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ 278 | II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ 279 | II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ 280 | II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ 281 | II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ 282 | II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ 283 | II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ 284 | II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ 285 | II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ 286 | 287 | state[0] += a; 288 | state[1] += b; 289 | state[2] += c; 290 | state[3] += d; 291 | 292 | /* Zeroize sensitive information. 293 | */ 294 | MD5_memset ((POINTER)x, 0, sizeof (x)); 295 | } 296 | 297 | /* Encodes input (UINT4) into output (unsigned char). Assumes len is 298 | a multiple of 4. 299 | */ 300 | static void Encode (output, input, len) 301 | unsigned char *output; 302 | UINT4 *input; 303 | unsigned int len; 304 | { 305 | unsigned int i, j; 306 | 307 | for (i = 0, j = 0; j < len; i++, j += 4) { 308 | output[j] = (unsigned char)(input[i] & 0xff); 309 | output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); 310 | output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); 311 | output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); 312 | } 313 | } 314 | 315 | /* Decodes input (unsigned char) into output (UINT4). Assumes len is 316 | a multiple of 4. 317 | */ 318 | static void Decode (output, input, len) 319 | UINT4 *output; 320 | unsigned char *input; 321 | unsigned int len; 322 | { 323 | unsigned int i, j; 324 | 325 | for (i = 0, j = 0; j < len; i++, j += 4) 326 | output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | 327 | (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); 328 | } 329 | 330 | /* Note: Replace "for loop" with standard memcpy if possible. 331 | */ 332 | 333 | static void MD5_memcpy (output, input, len) 334 | POINTER output; 335 | POINTER input; 336 | unsigned int len; 337 | { 338 | 339 | #ifndef USE_MEM 340 | unsigned int i; 341 | 342 | for (i = 0; i < len; i++) 343 | output[i] = input[i]; 344 | #else 345 | memcpy( output, input, len ); 346 | #endif 347 | } 348 | 349 | /* Note: Replace "for loop" with standard memset if possible. 350 | */ 351 | static void MD5_memset (output, value, len) 352 | POINTER output; 353 | int value; 354 | unsigned int len; 355 | { 356 | 357 | #ifndef USE_MEM 358 | unsigned int i; 359 | for (i = 0; i < len; i++) 360 | ((char *)output)[i] = (char)value; 361 | #else 362 | memset( output, value, len ); 363 | #endif 364 | } 365 | 366 | #endif /* ! HAVE_EXTERNAL_MD5 */ 367 | -------------------------------------------------------------------------------- /src/md5.h: -------------------------------------------------------------------------------- 1 | /* MD5.H - header file for MD5C.C 2 | */ 3 | 4 | 5 | /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All 6 | rights reserved. 7 | 8 | License to copy and use this software is granted provided that it 9 | is identified as the "RSA Data Security, Inc. MD5 Message-Digest 10 | Algorithm" in all material mentioning or referencing this software 11 | or this function. 12 | 13 | License is also granted to make and use derivative works provided 14 | that such works are identified as "derived from the RSA Data 15 | Security, Inc. MD5 Message-Digest Algorithm" in all material 16 | mentioning or referencing the derived work. 17 | 18 | RSA Data Security, Inc. makes no representations concerning either 19 | the merchantability of this software or the suitability of this 20 | software for any particular purpose. It is provided "as is" 21 | without express or implied warranty of any kind. 22 | 23 | These notices must be retained in any copies of any part of this 24 | documentation and/or software. 25 | */ 26 | 27 | #ifndef SIPSAK_MD5_H 28 | #define SIPSAK_MD5_H 29 | 30 | #ifdef HAVE_CONFIG_H 31 | # include "config.h" 32 | #endif 33 | 34 | #include "sipsak.h" 35 | 36 | #ifdef HAVE_FULL_OPENSSL 37 | # include 38 | #endif 39 | 40 | #ifdef HAVE_EXTERNAL_MD5 41 | 42 | # define MD5Init MD5_Init 43 | # define MD5Update MD5_Update 44 | # define MD5Final MD5_Final 45 | 46 | #else 47 | 48 | #include "md5global.h" 49 | 50 | /* MD5 context. */ 51 | typedef struct { 52 | UINT4 state[4]; /* state (ABCD) */ 53 | UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ 54 | unsigned char buffer[64]; /* input buffer */ 55 | } MD5_CTX; 56 | 57 | void MD5Init PROTO_LIST ((MD5_CTX *)); 58 | void MD5Update PROTO_LIST 59 | ((MD5_CTX *, unsigned char *, unsigned int)); 60 | void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); 61 | #endif 62 | #endif 63 | -------------------------------------------------------------------------------- /src/md5global.h: -------------------------------------------------------------------------------- 1 | /* GLOBAL.H - RSAREF types and constants 2 | * 3 | */ 4 | 5 | 6 | /* PROTOTYPES should be set to one if and only if the compiler supports 7 | function argument prototyping. 8 | The following makes PROTOTYPES default to 0 if it has not already 9 | been defined with C compiler flags. 10 | */ 11 | #ifndef PROTOTYPES 12 | #define PROTOTYPES 0 13 | #endif 14 | 15 | /* POINTER defines a generic pointer type */ 16 | typedef unsigned char *POINTER; 17 | 18 | #ifdef HAVE_STDINT_H 19 | # include 20 | typedef uint32_t UINT4; 21 | #else 22 | /* UINT4 defines a four byte word */ 23 | typedef unsigned long int UINT4; 24 | #endif 25 | 26 | /* PROTO_LIST is defined depending on how PROTOTYPES is defined above. 27 | If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it 28 | returns an empty list. 29 | */ 30 | #if PROTOTYPES 31 | #define PROTO_LIST(list) list 32 | #else 33 | #define PROTO_LIST(list) () 34 | #endif 35 | 36 | -------------------------------------------------------------------------------- /src/request.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2002-2004 Fhg Fokus 3 | * Copyright (C) 2004-2022 Nils Ohlmeier 4 | * 5 | * This file belongs to sipsak, a free sip testing tool. 6 | * 7 | * sipsak is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * sipsak is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | 18 | #include "sipsak.h" 19 | 20 | #ifdef HAVE_STRING_H 21 | # include 22 | #endif 23 | 24 | #include "request.h" 25 | #include "exit_code.h" 26 | #include "helper.h" 27 | #include "header_f.h" 28 | #include "transport.h" 29 | #include "sip_strings.h" 30 | 31 | /* create a valid sip header for the different modes */ 32 | void create_msg(int action, struct sipsak_msg_data *msg_data){ 33 | unsigned int c, d, len; 34 | char *req_buf_begin = msg_data->req_buff; 35 | 36 | if(msg_data->cseq_counter == 0) { 37 | fprintf(stderr, "error: CSeq 0 is not allowed\n"); 38 | exit_code(253, __PRETTY_FUNCTION__, "invalid CSeq 0"); 39 | } 40 | if (msg_data->req_buff == NULL) 41 | abort(); 42 | if (msg_data->username == NULL) 43 | msg_data->username = ""; 44 | c=(unsigned int)rand(); 45 | c+=msg_data->lport; 46 | d=(unsigned int)rand(); 47 | switch (action){ 48 | case REQ_REG: 49 | sprintf(msg_data->req_buff, 50 | "%s sip:%s%s" 51 | "%ssip:%s%s;tag=%x\r\n" 52 | "%ssip:%s%s\r\n" 53 | "%s%u@%s\r\n" 54 | "%s%i %s\r\n" 55 | "%s0\r\n" 56 | "%s70\r\n" 57 | "%s%s\r\n", 58 | REG_STR, msg_data->domainname, SIP20_STR, 59 | FROM_STR, msg_data->username, msg_data->domainname, c, 60 | TO_STR, msg_data->username, msg_data->domainname, 61 | CALL_STR, c, msg_data->fqdn, 62 | CSEQ_STR, msg_data->cseq_counter, REG_STR, 63 | CON_LEN_STR, 64 | MAX_FRW_STR, 65 | UA_STR, UA_VAL_STR); 66 | msg_data->req_buff += strlen(msg_data->req_buff); 67 | if (msg_data->contact_uri!=NULL) { 68 | sprintf(msg_data->req_buff, "%s%i\r\n" 69 | "%s%s\r\n\r\n", 70 | EXP_STR, msg_data->expires_t, 71 | CONT_STR, msg_data->contact_uri); 72 | } 73 | else if (msg_data->empty_contact == 0) { 74 | sprintf(msg_data->req_buff, "%s%i\r\n" 75 | "%ssip:%s%s:%i", 76 | EXP_STR, msg_data->expires_t, 77 | CONT_STR, msg_data->username, msg_data->fqdn, msg_data->lport); 78 | msg_data->req_buff += strlen(msg_data->req_buff); 79 | if (msg_data->transport != SIP_UDP_TRANSPORT) 80 | sprintf(msg_data->req_buff, "%s%s\r\n\r\n", TRANSPORT_PARAMETER_STR, 81 | transport_str); 82 | else 83 | sprintf(msg_data->req_buff, "\r\n\r\n"); 84 | } 85 | else{ 86 | sprintf(msg_data->req_buff, "\r\n"); 87 | } 88 | add_via(req_buf_begin, msg_data->fqdn, msg_data->lport); 89 | break; 90 | case REQ_REM: 91 | sprintf(msg_data->req_buff, 92 | "%s sip:%s%s" 93 | "%ssip:%s%s;tag=%x\r\n" 94 | "%ssip:%s%s\r\n" 95 | "%s%u@%s\r\n" 96 | "%s%i %s\r\n" 97 | "%s%i\r\n" 98 | "%s0\r\n" 99 | "%s70\r\n" 100 | "%s%s\r\n" 101 | "%ssip:%s%s:%i;%s0", 102 | REG_STR, msg_data->domainname, SIP20_STR, 103 | FROM_STR, msg_data->username, msg_data->domainname, c, 104 | TO_STR, msg_data->username, msg_data->domainname, 105 | CALL_STR, c, msg_data->fqdn, 106 | CSEQ_STR, msg_data->cseq_counter, REG_STR, 107 | EXP_STR, msg_data->expires_t, 108 | CON_LEN_STR, 109 | MAX_FRW_STR, 110 | UA_STR, UA_VAL_STR, 111 | CONT_STR, msg_data->username, msg_data->fqdn, msg_data->lport, CON_EXP_STR); 112 | msg_data->req_buff += strlen(msg_data->req_buff); 113 | if (msg_data->transport != SIP_UDP_TRANSPORT) { 114 | sprintf(msg_data->req_buff, "\r\n\r\n"); 115 | } 116 | else { 117 | sprintf(msg_data->req_buff, "%s%s\r\n\r\n", TRANSPORT_PARAMETER_STR, 118 | transport_str); 119 | } 120 | add_via(req_buf_begin, msg_data->fqdn, msg_data->lport); 121 | break; 122 | case REQ_INV: 123 | sprintf(msg_data->req_buff, 124 | "%s sip:%s%s%s" 125 | "%ssip:%s%s\r\n" 126 | "%s%u@%s\r\n" 127 | "%s%i %s\r\n" 128 | "%s0\r\n" 129 | "%ssip:sipsak@%s:%i\r\n" 130 | "%sDONT ANSWER this test call!\r\n" 131 | "%s70\r\n" 132 | "%s%s\r\n", 133 | INV_STR, msg_data->username, msg_data->domainname, SIP20_STR, 134 | TO_STR, msg_data->username, msg_data->domainname, 135 | CALL_STR, c, msg_data->fqdn, 136 | CSEQ_STR, msg_data->cseq_counter, INV_STR, 137 | CON_LEN_STR, 138 | CONT_STR, msg_data->fqdn, msg_data->lport, 139 | SUB_STR, 140 | MAX_FRW_STR, 141 | UA_STR, UA_VAL_STR); 142 | msg_data->req_buff += strlen(msg_data->req_buff); 143 | if (msg_data->from_uri) { 144 | sprintf(msg_data->req_buff, 145 | "%s%s;tag=%x\r\n" 146 | "\r\n", 147 | FROM_STR, msg_data->from_uri, c); 148 | } 149 | else { 150 | sprintf(msg_data->req_buff, 151 | "%ssip:sipsak@%s:%i;tag=%x\r\n" 152 | "\r\n", 153 | FROM_STR, msg_data->fqdn, msg_data->lport, c); 154 | } 155 | add_via(req_buf_begin, msg_data->fqdn, msg_data->lport); 156 | sprintf(msg_data->repl_buff, 157 | "%s" 158 | "%ssip:sipsak@%s:%i;tag=%x\r\n" 159 | "%ssip:%s%s;tag=%o%o\r\n" 160 | "%s%u@%s\r\n" 161 | "%s%i %s\r\n" 162 | "%s0\r\n" 163 | "%ssip:sipsak_conf@%s:%i\r\n" 164 | "%s%s\r\n" 165 | "\r\n", 166 | SIP200_STR, 167 | FROM_STR, msg_data->fqdn, msg_data->lport, c, 168 | TO_STR, msg_data->username, msg_data->domainname, c, d, 169 | CALL_STR, c, msg_data->fqdn, 170 | CSEQ_STR, msg_data->cseq_counter, INV_STR, 171 | CON_LEN_STR, 172 | CONT_STR, msg_data->fqdn, msg_data->lport, 173 | UA_STR, UA_VAL_STR); 174 | break; 175 | case REQ_MES: 176 | sprintf(msg_data->req_buff, 177 | "%s sip:%s%s%s" 178 | "%ssip:%s%s\r\n" 179 | "%s%u@%s\r\n" 180 | "%s%i %s\r\n" 181 | "%s%s\r\n" 182 | "%s70\r\n" 183 | "%s%s\r\n", 184 | MES_STR, msg_data->username, msg_data->domainname, SIP20_STR, 185 | TO_STR, msg_data->username, msg_data->domainname, 186 | CALL_STR, c, msg_data->fqdn, 187 | CSEQ_STR, msg_data->cseq_counter, MES_STR, 188 | CON_TYP_STR, TXT_PLA_STR, 189 | MAX_FRW_STR, 190 | UA_STR, UA_VAL_STR); 191 | msg_data->req_buff += strlen(msg_data->req_buff); 192 | if (msg_data->from_uri) { 193 | sprintf(msg_data->req_buff, 194 | "%s%s;tag=%x\r\n", 195 | FROM_STR, msg_data->from_uri, c); 196 | } 197 | else { 198 | sprintf(msg_data->req_buff, 199 | "%ssip:sipsak@%s:%i;tag=%x\r\n", 200 | FROM_STR, msg_data->fqdn, msg_data->lport, c); 201 | } 202 | msg_data->req_buff += strlen(msg_data->req_buff); 203 | if (msg_data->mes_body) { 204 | len = strlen(msg_data->mes_body); 205 | } 206 | else { 207 | len = SIPSAK_MES_STR_LEN + strlen(msg_data->username); 208 | } 209 | sprintf(msg_data->req_buff, "%s%u\r\n", CON_LEN_STR, len); 210 | msg_data->req_buff += strlen(msg_data->req_buff); 211 | if (msg_data->con_dis) { 212 | sprintf(msg_data->req_buff, "%s%s\r\n", CON_DIS_STR, msg_data->con_dis); 213 | msg_data->req_buff += strlen(msg_data->req_buff); 214 | } 215 | sprintf(msg_data->req_buff, "\r\n"); 216 | msg_data->req_buff += 2; 217 | if (msg_data->mes_body) { 218 | sprintf(msg_data->req_buff, 219 | "%s", 220 | msg_data->mes_body); 221 | } 222 | else { 223 | sprintf(msg_data->req_buff, "%s%s", SIPSAK_MES_STR, msg_data->username); 224 | msg_data->req_buff += strlen(msg_data->req_buff) - 1; 225 | *(msg_data->req_buff) = '.'; 226 | } 227 | add_via(req_buf_begin, msg_data->fqdn, msg_data->lport); 228 | sprintf(msg_data->repl_buff, 229 | "%s" 230 | "%ssip:sipsak@%s:%i;tag=%x\r\n" 231 | "%ssip:%s%s;tag=%o%o\r\n" 232 | "%s%u@%s\r\n" 233 | "%s%i %s\r\n" 234 | "%s0\r\n" 235 | "%s%s\r\n" 236 | "\r\n", 237 | SIP200_STR, 238 | FROM_STR, msg_data->fqdn, msg_data->lport, c, 239 | TO_STR, msg_data->username, msg_data->domainname, c, d, 240 | CALL_STR, c, msg_data->fqdn, 241 | CSEQ_STR, msg_data->cseq_counter, MES_STR, 242 | CON_LEN_STR, 243 | UA_STR, UA_VAL_STR); 244 | break; 245 | case REQ_OPT: 246 | sprintf(msg_data->req_buff, 247 | "%s sip:%s%s%s" 248 | "%ssip:sipsak@%s:%i;tag=%x\r\n" 249 | "%ssip:%s%s\r\n" 250 | "%s%u@%s\r\n" 251 | "%s%i %s\r\n" 252 | "%ssip:sipsak@%s:%i\r\n" 253 | "%s0\r\n" 254 | "%s70\r\n" 255 | "%s%s\r\n" 256 | "%s%s\r\n" 257 | "\r\n", 258 | OPT_STR, msg_data->username, msg_data->domainname, SIP20_STR, 259 | FROM_STR, msg_data->fqdn, msg_data->lport, c, 260 | TO_STR, msg_data->username, msg_data->domainname, 261 | CALL_STR, c, msg_data->fqdn, 262 | CSEQ_STR, msg_data->cseq_counter, OPT_STR, 263 | CONT_STR, msg_data->fqdn, msg_data->lport, 264 | CON_LEN_STR, 265 | MAX_FRW_STR, 266 | UA_STR, UA_VAL_STR, 267 | ACP_STR, TXT_PLA_STR); 268 | add_via(req_buf_begin, msg_data->fqdn, msg_data->lport); 269 | break; 270 | case REQ_FLOOD: 271 | sprintf(msg_data->req_buff, 272 | "%s sip:%s%s%s" 273 | "%s%s %s:9;branch=z9hG4bK.%08x\r\n" 274 | "%ssip:sipsak@%s:9;tag=%x\r\n" 275 | "%ssip:%s%s\r\n" 276 | "%s%u@%s\r\n" 277 | "%s%i %s\r\n" 278 | "%ssip:sipsak@%s:9\r\n" 279 | "%s0\r\n" 280 | "%s70\r\n" 281 | "%s%s\r\n" 282 | "\r\n", 283 | FLOOD_METH, msg_data->username, msg_data->domainname, SIP20_STR, 284 | VIA_SIP_STR, TRANSPORT_UDP_STR, msg_data->fqdn, d, 285 | FROM_STR, msg_data->fqdn, c, 286 | TO_STR, msg_data->username, msg_data->domainname, 287 | CALL_STR, c, msg_data->fqdn, 288 | CSEQ_STR, msg_data->cseq_counter, FLOOD_METH, 289 | CONT_STR, msg_data->fqdn, 290 | CON_LEN_STR, 291 | MAX_FRW_STR, 292 | UA_STR, UA_VAL_STR); 293 | break; 294 | case REQ_RAND: 295 | sprintf(msg_data->req_buff, 296 | "%s sip:%s%s" 297 | "%ssip:sipsak@%s:%i;tag=%x\r\n" 298 | "%ssip:%s\r\n" 299 | "%s%u@%s\r\n" 300 | "%s%i %s\r\n" 301 | "%ssipsak@%s:%i\r\n" 302 | "%s0\r\n" 303 | "%s70\r\n" 304 | "%s%s\r\n" 305 | "\r\n", 306 | OPT_STR, msg_data->domainname, SIP20_STR, 307 | FROM_STR, msg_data->fqdn, msg_data->lport, c, 308 | TO_STR, msg_data->domainname, 309 | CALL_STR, c, msg_data->fqdn, 310 | CSEQ_STR, msg_data->cseq_counter, OPT_STR, 311 | CONT_STR, msg_data->fqdn, msg_data->lport, 312 | CON_LEN_STR, 313 | MAX_FRW_STR, 314 | UA_STR, UA_VAL_STR); 315 | add_via(req_buf_begin, msg_data->fqdn, msg_data->lport); 316 | break; 317 | default: 318 | fprintf(stderr, "error: unknown request type to create\n"); 319 | exit_code(2, __PRETTY_FUNCTION__, "unknown request type requested"); 320 | break; 321 | } 322 | if (msg_data->headers) { 323 | insert_header(req_buf_begin, msg_data->headers, 1); 324 | if (msg_data->repl_buff) 325 | insert_header(msg_data->repl_buff, msg_data->headers, 1); 326 | } 327 | } 328 | 329 | -------------------------------------------------------------------------------- /src/request.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2002-2004 Fhg Fokus 3 | * Copyright (C) 2004-2022 Nils Ohlmeier 4 | * 5 | * This file belongs to sipsak, a free sip testing tool. 6 | * 7 | * sipsak is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * sipsak is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | 18 | #ifndef SIPSAK_REQUEST_H 19 | #define SIPSAK_REQUEST_H 20 | 21 | struct sipsak_msg_data { 22 | int cseq_counter; 23 | int lport; 24 | int expires_t; 25 | int empty_contact; 26 | unsigned int transport; 27 | char *req_buff; 28 | char *repl_buff; 29 | char *username; 30 | char *usern; 31 | char *domainname; 32 | char *contact_uri; 33 | char *con_dis; 34 | char *from_uri; 35 | char *mes_body; 36 | char *headers; 37 | char *fqdn; 38 | }; 39 | 40 | void create_msg(int action, struct sipsak_msg_data *data); 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/shoot.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2002-2004 Fhg Fokus 3 | * Copyright (C) 2004-2022 Nils Ohlmeier 4 | * 5 | * This file belongs to sipsak, a free sip testing tool. 6 | * 7 | * sipsak is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * sipsak is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | 18 | #ifndef SIPSAK_SHOOT_H 19 | #define SIPSAK_SHOOT_H 20 | 21 | #ifdef HAVE_CONFIG_H 22 | # include "config.h" 23 | #endif 24 | #ifdef HAVE_REGEX_H 25 | # include 26 | #endif 27 | 28 | #define LPORT_STR_LEN 6 29 | 30 | struct sipsak_regexp { 31 | regex_t redexp; 32 | regex_t proexp; 33 | regex_t okexp; 34 | regex_t tmhexp; 35 | regex_t errexp; 36 | regex_t authexp; 37 | regex_t replyexp; 38 | regex_t *optionsexp; 39 | }; 40 | 41 | enum usteps { 42 | REG_REP, 43 | INV_RECV, 44 | INV_OK_RECV, 45 | INV_ACK_RECV, 46 | MES_RECV, 47 | MES_OK_RECV, 48 | UNREG_REP 49 | }; 50 | 51 | void shoot(char *buff, int buff_size, struct sipsak_options *options); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/sip_strings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2002-2004 Fhg Fokus 3 | * Copyright (C) 2004-2021 Nils Ohlmeier 4 | * 5 | * This file belongs to sipsak, a free sip testing tool. 6 | * 7 | * sipsak is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * sipsak is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | 18 | #ifndef SIP_STRINGS_H 19 | #define SIP_STRINGS_H 20 | 21 | #define VIA_SIP_STR "Via: SIP/2.0/" 22 | #define VIA_SIP_STR_LEN (sizeof(VIA_SIP_STR) - 1) 23 | 24 | #define SIP20_STR " SIP/2.0\r\n" 25 | #define SIP20_STR_LEN (sizeof(SIP20_STR) - 1) 26 | 27 | #define SIP200_STR "SIP/2.0 200 OK\r\n" 28 | #define SIP200_STR_LEN (sizeof(SIP200_STR) - 1) 29 | 30 | #define INV_STR "INVITE" 31 | #define INV_STR_LEN (sizeof(INV_STR) - 1) 32 | 33 | #define REG_STR "REGISTER" 34 | #define REG_STR_LEN (sizeof(REG_STR) - 1) 35 | 36 | #define OPT_STR "OPTIONS" 37 | #define OPT_STR_LEN (sizeof(OPT_STR) - 1) 38 | 39 | #define MES_STR "MESSAGE" 40 | #define MES_STR_LEN (sizeof(MES_STR) - 1) 41 | 42 | #define ACK_STR "ACK" 43 | #define ACK_STR_LEN (sizeof(ACK_STR) - 1) 44 | 45 | #define FROM_STR "From: " 46 | #define FROM_STR_LEN (sizeof(FROM_STR) - 1) 47 | #define FROM_SHORT_STR "\nf: " 48 | #define FROM_SHORT_STR_LEN (sizeof(FROM_SHORT_STR) - 1) 49 | 50 | #define TO_STR "To: " 51 | #define TO_STR_LEN (sizeof(TO_STR) - 1) 52 | #define TO_SHORT_STR "\nt: " 53 | #define TO_SHORT_STR_LEN (sizeof(TO_SHORT_STR) - 1) 54 | 55 | #define VIA_STR "Via: " 56 | #define VIA_STR_LEN (sizeof(VIA_STR) - 1) 57 | #define VIA_SHORT_STR "\nv: " 58 | #define VIA_SHORT_STR_LEN (sizeof(VIA_SHORT_STR) - 1) 59 | 60 | #define CALL_STR "Call-ID: " 61 | #define CALL_STR_LEN (sizeof(CALL_STR) - 1) 62 | #define CALL_SHORT_STR "\ni: " 63 | #define CALL_SHORT_STR_LEN (sizeof(CALL_SHORT_STR) - 1) 64 | 65 | #define MAX_FRW_STR "Max-Forwards: " 66 | #define MAX_FRW_STR_LEN (sizeof(MAX_FRW_STR) - 1) 67 | 68 | #define CSEQ_STR "CSeq: " 69 | #define CSEQ_STR_LEN (sizeof(CSEQ_STR) - 1) 70 | 71 | #define CONT_STR "Contact: " 72 | #define CONT_STR_LEN (sizeof(CONT_STR) - 1) 73 | #define CONT_SHORT_STR "\nm: " 74 | #define CONT_SHORT_STR_LEN (sizeof(CONT_SHORT_STR) - 1) 75 | 76 | #define CON_TYP_STR "Content-Type: " 77 | #define CON_TYP_STR_LEN (sizeof(CON_TYP_STR) - 1) 78 | #define CON_TYP_SHORT_STR "\nc: " 79 | #define CON_TYP_SHORT_STR_LEN (sizeof(CON_TYP_SHORT_STR) - 1) 80 | 81 | #define CON_DIS_STR "Content-Disposition: " 82 | #define CON_DIS_STR_LEN (sizeof(CON_DIS_STR) - 1) 83 | 84 | #define TXT_PLA_STR "text/plain" 85 | #define TXT_PLA_STR_LEN (sizeof(TXT_PLA_STR) - 1) 86 | 87 | #define ACP_STR "Accept: " 88 | #define ACP_STR_LEN (sizeof(ACP_STR) - 1) 89 | 90 | #define CON_LEN_STR "Content-Length: " 91 | #define CON_LEN_STR_LEN (sizeof(CON_LEN_STR) - 1) 92 | #define CON_LEN_SHORT_STR "\nl: " 93 | #define CON_LEN_SHORT_STR_LEN (sizeof(CON_LEN_SHORT_STR) - 1) 94 | 95 | #define RR_STR "Record-Route: " 96 | #define RR_STR_LEN (sizeof(RR_STR) - 1) 97 | 98 | #define ROUTE_STR "Route: " 99 | #define ROUTE_STR_LEN (sizeof(ROUTE_STR) - 1) 100 | 101 | #define SIPSAK_MES_STR "test message from SIPsak for user " 102 | #define SIPSAK_MES_STR_LEN (sizeof(SIPSAK_MES_STR) - 1) 103 | 104 | #define EXP_STR "Expires: " 105 | #define EXP_STR_LEN (sizeof(EXP_STR) - 1) 106 | 107 | #define CON_EXP_STR "expires=" 108 | #define CON_EXP_STR_LEN (sizeof(CON_EXP_STR) - 1) 109 | 110 | #define WWWAUTH_STR "WWW-Authenticate: " 111 | #define WWWAUTH_STR_LEN (sizeof(WWWAUTH_STR) - 1) 112 | 113 | #define PROXYAUTH_STR "Proxy-Authenticate: " 114 | #define PROXYAUTH_STR_LEN (sizeof(PROXYAUTH_STR) - 1) 115 | 116 | #define AUTH_STR "Authorization: Digest " 117 | #define AUTH_STR_LEN (sizeof(AUTH_STR) - 1) 118 | 119 | #define PROXYAUZ_STR "Proxy-Authorization: Digest " 120 | #define PROXYAUZ_STR_LEN (sizeof(PROXYAUZ_STR) - 1) 121 | 122 | #define ALGO_STR "algorithm=" 123 | #define ALGO_STR_LEN (sizeof(ALGO_STR) - 1) 124 | 125 | #define MD5_STR "MD5, " 126 | #define MD5_STR_LEN (sizeof(MD5_STR) - 1) 127 | 128 | #define SHA1_STR "SHA1, " 129 | #define SHA1_STR_LEN (sizeof(SHA1_STR) - 1) 130 | 131 | #define SHA256_STR "SHA-256, " 132 | #define SHA256_STR_LEN (sizeof(SHA256_STR) - 1) 133 | 134 | #define REALM_STR "realm=" 135 | #define REALM_STR_LEN (sizeof(REALM_STR) - 1) 136 | 137 | #define OPAQUE_STR "opaque=" 138 | #define OPAQUE_STR_LEN (sizeof(OPAQUEE_STR) - 1) 139 | 140 | #define NONCE_STR "nonce=" 141 | #define NONCE_STR_LEN (sizeof(NONCE_STR) - 1) 142 | 143 | #define RESPONSE_STR "response=" 144 | #define RESPONSE_STR_LEN (sizeof(RESPONSE_STR) - 1) 145 | 146 | #define QOP_STR "qop=" 147 | #define QOP_STR_LEN (sizeof(QOP_STR) - 1) 148 | 149 | #define QOPAUTH_STR "auth" 150 | #define QOPAUTH_STR_LEN (sizeof(QOPAUTH_STR) - 1) 151 | 152 | #define NC_STR "nc=" 153 | #define NC_STR_LEN (sizeof(NC_STR) - 1) 154 | 155 | #define EMPTY_STR "" 156 | #define EMPTY_STR_LEN (sizeof(EMPTY_STR) - 1) 157 | 158 | #define UA_STR "User-Agent: " 159 | #define UA_STR_LEN (sizeof(UA_STR) - 1) 160 | 161 | #define SUB_STR "Subject: " 162 | #define SUB_STR_LEN (sizeof(SUB_STR) - 1) 163 | 164 | #define SIP100_STR "SIP/2.0 100" 165 | #define SIP100_STR_LEN (sizeof(SIP100_STR) - 1) 166 | 167 | #define TRANSPORT_PARAMETER_STR ";transport=" 168 | #define TRANSPORT_PARAMETER_STR_LEN (sizeof(TRANSPORT_PARAMETER_STR) - 1) 169 | 170 | #endif 171 | -------------------------------------------------------------------------------- /src/sipsak.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2002-2004 Fhg Fokus 3 | * Copyright (C) 2004-2022 Nils Ohlmeier 4 | * 5 | * This file belongs to sipsak, a free sip testing tool. 6 | * 7 | * sipsak is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * sipsak is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | 18 | #ifndef SIPSAK_H 19 | #define SIPSAK_H 20 | 21 | #if HAVE_CONFIG_H 22 | # include "config.h" 23 | #endif 24 | 25 | #ifdef HAVE_STDIO_H 26 | # include 27 | #endif 28 | #ifdef HAVE_STDLIB_H 29 | # include 30 | #endif 31 | #ifdef HAVE_SYS_TYPES_H 32 | # include 33 | #endif 34 | #ifdef HAVE_REGEX_H 35 | # include 36 | #endif 37 | #ifdef HAVE_SYS_PARAM_H 38 | # include 39 | #endif 40 | #ifdef HAVE_NETINET_IN_H 41 | # include 42 | #endif 43 | #ifndef INET_ADDRSTRLEN 44 | # define INET_ADDRSTRLEN 16 45 | #endif 46 | #ifdef HAVE_SIGNAL_H 47 | # include 48 | #endif 49 | 50 | #ifdef HAVE_LIMITS_H 51 | # include 52 | #endif 53 | #ifndef INT_MAX 54 | # define INT_MAX 2147483648 55 | #endif 56 | 57 | #ifdef HAVE_STRCASESTR 58 | # define __USE_GNU 59 | # define STRCASESTR(s1,s2) strcasestr(s1,s2) 60 | #else 61 | # define STRCASESTR(s1,s2) strstr(s1,s2) 62 | #endif 63 | #ifdef HAVE_STRNCASECMP 64 | # define STRNCASECMP(s1,s2,s3) strncasecmp(s1,s2,s3) 65 | #else 66 | # define STRNCASECMP(s1,s2,s3) strncmp(s1,s2,s3) 67 | #endif 68 | #ifdef HAVE_STRING_H 69 | # include 70 | #endif 71 | 72 | #ifdef HAVE_GNUTLS 73 | # define USE_GNUTLS 74 | # ifndef SIPSAK_NO_TLS 75 | # define WITH_TLS_TRANSP 1 76 | # endif 77 | # include 78 | #else 79 | # ifdef HAVE_OPENSSL_MD5_H 80 | # ifdef HAVE_CRYPTO_WITH_MD5 81 | # define HAVE_FULL_OPENSSL 82 | # define HAVE_EXTERNAL_MD5 83 | # define USE_OPENSSL 84 | # include 85 | # endif 86 | # endif 87 | #endif 88 | 89 | #ifdef HAVE_OPENSSL_SHA_H 90 | # ifdef HAVE_CRYPTO_WITH_SHA1 91 | # define HAVE_OPENSSL_SHA1 92 | # endif 93 | #endif 94 | 95 | #ifdef SIPSAK_PRINT_DBG 96 | # define DEBUG 1 97 | #endif 98 | 99 | #ifndef REG_NOERROR 100 | # define REG_NOERROR 0 101 | #endif 102 | 103 | #ifdef HAVE_SYS_PARAM_H 104 | # ifdef MAXHOSTNAMELEN 105 | # define FQDN_SIZE MAXHOSTNAMELEN + 1 106 | # else 107 | # define FQDN_SIZE 100 108 | # endif 109 | #else 110 | # define FQDN_SIZE 100 111 | #endif 112 | 113 | #ifdef HAVE_CONFIG_H 114 | # define SIP_T1 DEFAULT_TIMEOUT 115 | #else 116 | # define SIP_T1 500 117 | #endif 118 | 119 | #define SIP_T2 8*SIP_T1 120 | 121 | #define SIPSAK_VERSION PACKAGE_VERSION 122 | #define UA_VAL_STR "sipsak " SIPSAK_VERSION 123 | #define BUFSIZE 4096 124 | 125 | #define SIPSAK_MAX_PASSWD_LEN 20 126 | 127 | #define REQ_REG 1 128 | #define REQ_REM 2 129 | #define REQ_INV 3 130 | #define REQ_MES 4 131 | #define REQ_OPT 5 132 | #define REQ_FLOOD 6 133 | #define REQ_RAND 7 134 | 135 | #define SIP_TLS_TRANSPORT 1 136 | #define SIP_TCP_TRANSPORT 2 137 | #define SIP_UDP_TRANSPORT 3 138 | 139 | #define TRANSPORT_TLS_STR "TLS" 140 | #define TRANSPORT_TCP_STR "TCP" 141 | #define TRANSPORT_UDP_STR "UDP" 142 | #define TRANSPORT_STR_LEN 3 143 | 144 | #define USRLOC_EXP_DEF 15 145 | #define FLOOD_METH "OPTIONS" 146 | 147 | #define SIPSAK_HASHLEN_MD5 16 148 | #define SIPSAK_HASHHEXLEN_MD5 2 * SIPSAK_HASHLEN_MD5 149 | #ifdef HAVE_OPENSSL_SHA1 150 | # define SIPSAK_HASHLEN_SHA1 20 151 | # define SIPSAK_HASHHEXLEN_SHA1 2 * SIPSAK_HASHLEN_SHA1 152 | # define SIPSAK_HASHLEN_SHA256 32 153 | # define SIPSAK_HASHHEXLEN_SHA256 2 * SIPSAK_HASHLEN_SHA256 154 | # define SIPSAK_HASHLEN SIPSAK_HASHLEN_SHA256 155 | #else 156 | # define SIPSAK_HASHLEN SIPSAK_HASHLEN_MD5 157 | #endif 158 | #define SIPSAK_HASHHEXLEN 2 * SIPSAK_HASHLEN 159 | 160 | extern int verbose; 161 | 162 | enum sipsak_modes { SM_UNDEFINED, SM_USRLOC, SM_USRLOC_INVITE, SM_USRLOC_MESSAGE, SM_INVITE, SM_MESSAGE, SM_FLOOD, SM_TRACE, SM_RANDTRASH }; 163 | 164 | struct sipsak_options { 165 | int timing; 166 | int namebeg; 167 | int nameend; 168 | int empty_contact; 169 | int redirects; 170 | int timer_final; 171 | int file_b; 172 | int replace_b; 173 | int via_ins; 174 | int lport; 175 | int rport; 176 | int fix_crlf; 177 | int maxforw; 178 | int numeric; 179 | int sleep_ms; 180 | int outbound_proxy; 181 | int processes; 182 | int randtrash; 183 | int trashchar; 184 | int uri_b; 185 | int symmetric; 186 | int warning_ext; 187 | int nagios_warn; 188 | int expires_t; 189 | int rand_rem; 190 | int timer_t1; 191 | #ifdef WITH_TLS_TRANSP 192 | int ignore_ca_fail; 193 | #endif 194 | enum sipsak_modes mode; 195 | char *password; 196 | char *mes_body; 197 | char *from_uri; 198 | char *contact_uri; 199 | char *replace_str; 200 | char *hostname; 201 | char *headers; 202 | char *authhash; 203 | char *local_ip; 204 | char *con_dis; 205 | char *username; 206 | char *domainname; 207 | char *auth_username; 208 | #ifdef WITH_TLS_TRANSP 209 | char *cert_file; 210 | char *ca_file; 211 | #endif 212 | unsigned int transport; 213 | unsigned long address; 214 | regex_t *regex; 215 | }; 216 | 217 | #endif 218 | -------------------------------------------------------------------------------- /src/transport.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2005-2022 Nils Ohlmeier 3 | * 4 | * This file belongs to sipsak, a free sip testing tool. 5 | * 6 | * sipsak is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * sipsak is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | */ 16 | 17 | #ifndef SIPSAK_TRANSPORT_H 18 | #define SIPSAK_TRANSPORT_H 19 | 20 | #include "sipsak.h" 21 | #include "shoot.h" 22 | 23 | #include 24 | #ifdef HAVE_SYS_TIME_H 25 | # include 26 | #endif 27 | #ifdef HAVE_SYS_SOCKET_H 28 | # include 29 | #endif 30 | 31 | struct sipsak_sr_time { 32 | struct timeval sendtime; 33 | struct timeval recvtime; 34 | struct timeval firstsendt; 35 | struct timeval starttime; 36 | struct timeval delaytime; 37 | int timer_t1; 38 | int timer_t2; 39 | int timer_final; 40 | int timing; 41 | }; 42 | 43 | struct sipsak_con_data { 44 | struct sockaddr_in adr; 45 | unsigned int transport; 46 | unsigned long address; 47 | int csock; 48 | int usock; 49 | int dontsend; 50 | int dontrecv; 51 | int connected; 52 | int symmetric; 53 | int lport; 54 | int rport; 55 | char *buf_tmp; 56 | int buf_tmp_size; 57 | }; 58 | 59 | struct sipsak_counter { 60 | int send_counter; 61 | int retrans_r_c; 62 | int retrans_s_c; 63 | int randretrys; 64 | int run; 65 | int namebeg; 66 | int nameend; 67 | }; 68 | 69 | struct sipsak_delay { 70 | int retryAfter; 71 | double big_delay; 72 | double small_delay; 73 | double all_delay; 74 | }; 75 | 76 | extern char *transport_str; 77 | 78 | void init_network(struct sipsak_con_data *cd, char *local_ip 79 | #ifdef WITH_TLS_TRANSP 80 | , char *ca_file 81 | #endif 82 | ); 83 | 84 | void shutdown_network(); 85 | 86 | void send_message(char* mes, struct sipsak_con_data *cd, 87 | struct sipsak_counter *sc, struct sipsak_sr_time *srt); 88 | 89 | int recv_message(char *buf, int size, int inv_trans, 90 | struct sipsak_delay *sd, struct sipsak_sr_time *srt, 91 | struct sipsak_counter *count, struct sipsak_con_data *cd, 92 | struct sipsak_regexp *reg, enum sipsak_modes mode, int cseq_counter, 93 | char *request, char *response); 94 | 95 | int set_target(struct sockaddr_in *adr, unsigned long target, int port, 96 | int socket, int connected, unsigned int transport, char *domainname 97 | #ifdef WITH_TLS_TRANSP 98 | , int ignore_ca_fail 99 | #endif 100 | ); 101 | #endif 102 | -------------------------------------------------------------------------------- /tests/check_auth.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2005-2022 Nils Ohlmeier 3 | * 4 | * This file belongs to sipsak, a free sip testing tool. 5 | * 6 | * sipsak is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * sipsak is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | */ 16 | #include "../config.h" 17 | 18 | #include 19 | 20 | #ifdef HAVE_CHECK_H 21 | 22 | #include 23 | #include "../src/auth.h" 24 | #include "../src/sipsak.h" 25 | 26 | #define RUNNING_CHECK 1 27 | 28 | void shutdown_network() {}; 29 | 30 | int verbose = 99; 31 | 32 | int expected_exit_code = -1; 33 | char *expected_exit_reason = NULL; 34 | int expected_exit_code_called = 0; 35 | 36 | void set_expected_exit_code(int code, char *reason) { 37 | expected_exit_code = code; 38 | expected_exit_reason = reason; 39 | expected_exit_code_called = 0; 40 | } 41 | 42 | void exit_code(int code, const char *function, const char *reason) { 43 | if (expected_exit_code == -1) { 44 | ck_abort_msg("Unexpected call to exit_code() with code %i at %s: %s", 45 | code, function, reason); 46 | } 47 | expected_exit_code_called = 1; 48 | ck_assert_msg(expected_exit_code == code, "Expected call to exit_code() with wrong code number"); 49 | ck_assert_str_eq(expected_exit_reason, reason); 50 | }; 51 | 52 | START_TEST (test_insert_auth_md5) { 53 | char message1[BUFSIZE] = "REGISTER test@example.org SIP/2.0\r\nbarfoo\r\n"; 54 | char auth_response[BUFSIZE] = "401\r\nWWW-Authenticate: Digest algorithm=MD5,nonce=1234567890,realm=example.org\r\n"; 55 | char username[] = "testuser"; 56 | char password[] = "helloworld"; 57 | 58 | const char expected1[] = "REGISTER test@example.org SIP/2.0\r\nAuthorization: Digest username=\"testuser\", uri=\"test@example.org\", algorithm=MD5, realm=example.org, nonce=1234567890, response=\"6a1ad69841f79661cda113d0dff8ab3d\"\r\nbarfoo\r\n"; 59 | 60 | insert_auth(&message1[0], &auth_response[0], &username[0], &password[0], 61 | NULL, NULL, 0, 0); 62 | 63 | ck_assert_msg(strcmp(&message1[0], &expected1[0]) == 0, 64 | "insert_auth() 'basic' resulted in '%s' instead of '%s'", &message1[0], &expected1[0]); 65 | 66 | char message2[BUFSIZE] = "INVITE test@example.org SIP/2.0\r\nbarfoo\r\n"; 67 | char auth_username[] = "authuser"; 68 | 69 | const char expected2[] = "INVITE test@example.org SIP/2.0\r\nAuthorization: Digest username=\"authuser\", uri=\"test@example.org\", algorithm=MD5, realm=example.org, nonce=1234567890, response=\"97b2d3f13a5484a471c681faf7ca14b1\"\r\nbarfoo\r\n"; 70 | 71 | insert_auth(&message2[0], &auth_response[0], NULL, &password[0], 72 | &auth_username[0], NULL, 0, 0); 73 | 74 | ck_assert_msg(strcmp(&message2[0], &expected2[0]) == 0, 75 | "insert_auth() 'authusername' resulted in '%s' instead of '%s'", &message2[0], &expected2[0]); 76 | 77 | char message3[BUFSIZE] = "MESSAGE test@example.org SIP/2.0\r\nbarfoo\r\n"; 78 | 79 | const char expected3[] = "MESSAGE test@example.org SIP/2.0\r\nAuthorization: Digest username=\"testuser1\", uri=\"test@example.org\", algorithm=MD5, realm=example.org, nonce=1234567890, response=\"dcb615fe24c81241d6fa0c533d153e51\"\r\nbarfoo\r\n"; 80 | 81 | insert_auth(&message3[0], &auth_response[0], &username[0], &password[0], 82 | NULL, NULL, 1, 1); 83 | 84 | ck_assert_msg(strcmp(&message3[0], &expected3[0]) == 0, 85 | "insert_auth() 'namebegin' resulted in '%s' instead of '%s'", &message3[0], &expected3[0]); 86 | 87 | char message4[BUFSIZE] = "foobar test@example.org SIP/2.0\r\nbarfoo\r\n"; 88 | char authhash[] = "dcb615fe24c81241d6fa0c533d153e51"; 89 | 90 | const char expected4[] = "foobar test@example.org SIP/2.0\r\nAuthorization: Digest username=\"testuser\", uri=\"test@example.org\", algorithm=MD5, realm=example.org, nonce=1234567890, response=\"48d6b710677a1aca3a5424debf9e012a\"\r\nbarfoo\r\n"; 91 | 92 | insert_auth(&message4[0], &auth_response[0], &username[0], &password[0], 93 | NULL, &authhash[0], 0, 0); 94 | 95 | ck_assert_msg(strcmp(&message4[0], &expected4[0]) == 0, 96 | "insert_auth() 'authhash' resulted in '%s' instead of '%s'", 97 | &message4[0], &expected4[0]); 98 | 99 | char message5[BUFSIZE] = "ACK test@example.org SIP/2.0\r\nbarfoo\r\n"; 100 | char auth_response2[BUFSIZE] = "401\r\nWWW-Authenticate: Digest algorithm=MD5, realm=example.org, nonce=1234567890, opaque=sjw8fn3wbj5sfs,\r\n"; 101 | 102 | const char expected5[] = "ACK test@example.org SIP/2.0\r\nAuthorization: Digest username=\"testuser\", uri=\"test@example.org\", algorithm=MD5, realm=example.org, opaque=sjw8fn3wbj5sfs, nonce=1234567890, response=\"781a7065cb6c4ecba6fdccd0ef8190c5\"\r\nbarfoo\r\n"; 103 | 104 | insert_auth(&message5[0], &auth_response2[0], &username[0], &password[0], 105 | NULL, NULL, 0, 0); 106 | 107 | ck_assert_msg(strcmp(&message5[0], &expected5[0]) == 0, 108 | "insert_auth() 'opaque' resulted in '%s' instead of '%s'", 109 | &message5[0], &expected5[0]); 110 | 111 | /* 112 | char message6[BUFSIZE] = "INVITE test@example.org SIP/2.0\r\nbarfoo\r\n"; 113 | char auth_response3[BUFSIZE] = "401\r\nWWW-Authenticate: Digest algorithm=MD5, realm=example.org, qop=\"auth\", nonce=1234567890\r\n"; 114 | 115 | const char expected6[] = "INVITE test@example.org SIP/2.0\r\nAuthorization: Digest username=\"testuser\", uri=\"test@example.org\", algorithm=MD5, realm=example.org, nonce=1234567890, qop=auth, nc=00000001, cnonce=\"41a7\", response=\"78e1c78a0638d5e25fe430fb3e7946f8\"\r\nbarfoo\r\n"; 116 | 117 | insert_auth(&message6[0], &auth_response3[0], &username[0], &password[0], 118 | NULL, NULL, 0, 0); 119 | 120 | ck_assert_msg(strcmp(&message6[0], &expected6[0]) == 0, 121 | "insert_auth() 'qop=auth' resulted in '%s' instead of '%s'", 122 | &message6[0], &expected6[0]); 123 | 124 | char message7[BUFSIZE] = "INVITE test@example.org SIP/2.0\r\nbarfoo\r\n"; 125 | char auth_response4[BUFSIZE] = "401\r\nWWW-Authenticate: Digest algorithm=MD5, realm=example.org, opaque=vdjn5t8gvsjs,qop=\"auth\", nonce=1234567890\r\n"; 126 | 127 | const char expected7[] = "INVITE test@example.org SIP/2.0\r\nAuthorization: Digest username=\"testuser\", uri=\"test@example.org\", algorithm=MD5, realm=example.org, opaque=vdjn5t8gvsjs, nonce=1234567890, qop=auth, nc=00000002, cnonce=\"10d63af1\", response=\"78e43bf1d1aa928f701dcc8b3ab9aa97\"\r\nbarfoo\r\n"; 128 | 129 | insert_auth(&message7[0], &auth_response4[0], &username[0], &password[0], 130 | NULL, NULL, 0, 0); 131 | 132 | ck_assert_msg(strcmp(&message7[0], &expected7[0]) == 0, 133 | "insert_auth() 'opaque + qop' resulted in '%s' instead of '%s'", 134 | &message7[0], &expected7[0]); 135 | */ 136 | } 137 | END_TEST 138 | 139 | START_TEST (test_insert_auth_exits) { 140 | char message1[BUFSIZE] = "REGISTER test@example.org SIP/2.0\r\nbarfoo\r\n"; 141 | //char auth_response[BUFSIZE] = "401\r\nWWW-Authenticate: Digest algorithm=MD5,nonce=1234567890,realm=example.org\r\n"; 142 | char auth_response[BUFSIZE] = "401"; 143 | char username[] = "testuser"; 144 | char password[] = "helloworld"; 145 | 146 | set_expected_exit_code(3, "missing authentication header in reply"); 147 | insert_auth(&message1[0], &auth_response[0], &username[0], &password[0], 148 | NULL, NULL, 0, 0); 149 | ck_assert_int_eq(expected_exit_code_called, 1); 150 | 151 | /* 152 | char message2[BUFSIZE] = "REGISTER"; 153 | 154 | set_expected_exit_code(3, "missing new line in request"); 155 | insert_auth(&message2[0], &auth_response[0], &username[0], &password[0], 156 | NULL, NULL, 0, 0); 157 | ck_assert_int_eq(expected_exit_code_called, 1); 158 | */ 159 | } 160 | END_TEST 161 | 162 | Suite *auth_suite(void) { 163 | Suite *s = suite_create("auth"); 164 | 165 | TCase *tc_insert_auth_md5 = tcase_create("test_insert_auth_md5"); 166 | tcase_add_test(tc_insert_auth_md5, test_insert_auth_md5); 167 | 168 | TCase *tc_insert_auth_exits = tcase_create("test_insert_auth_exits"); 169 | tcase_add_test(tc_insert_auth_exits, test_insert_auth_exits); 170 | 171 | /* add test cases to suite */ 172 | suite_add_tcase(s, tc_insert_auth_md5); 173 | suite_add_tcase(s, tc_insert_auth_exits); 174 | 175 | return s; 176 | } 177 | 178 | int main(void) { 179 | int number_failed; 180 | Suite *s = auth_suite(); 181 | SRunner *sr = srunner_create(s); 182 | srunner_run_all(sr, CK_VERBOSE); 183 | number_failed = srunner_ntests_failed(sr); 184 | srunner_free(sr); 185 | return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 186 | } 187 | 188 | #else /* HAVE_CHECK_H */ 189 | 190 | #include 191 | int main(void) { 192 | printf("check_auth: !!! missing check unit test framework !!!\n"); 193 | return EXIT_FAILURE; 194 | } 195 | 196 | #endif /* HAVE_CHECK_H */ 197 | -------------------------------------------------------------------------------- /tests/check_header_f.c: -------------------------------------------------------------------------------- 1 | #include "../config.h" 2 | 3 | #include 4 | 5 | #ifdef HAVE_CHECK_H 6 | 7 | #include 8 | #include "../src/header_f.h" 9 | 10 | #define RUNNING_CHECK 1 11 | 12 | int verbose = 99; 13 | 14 | char *transport_str = "UDP"; 15 | 16 | void exit_code(int code, const char *function, const char *reason) { 17 | ck_abort_msg("Unexpected call to exit_code() with code %i at %s: %s", 18 | code, function, reason); 19 | }; 20 | 21 | START_TEST (test_get_cl) { 22 | /* failure cases */ 23 | ck_assert_msg(get_cl("") == -1, "get_cl(\"\") returned %d, instead of -1", get_cl("")); 24 | ck_assert_msg(get_cl("a") == -1, "get_cl(\"a\") returned %d, instead of -1", get_cl("a")); 25 | 26 | /* success cases */ 27 | ck_assert_msg(get_cl("Content-Length: 123") == 123, "get_cl(\"123\") returned %d, instead of 123", get_cl("Content_Length: 123")); 28 | ck_assert_msg(get_cl("Content-Length: 321\r\n") == 321, "get_cl(\"321\") returned %d, instead of 321", get_cl("Content_Length: 321\r\n")); 29 | ck_assert_msg(get_cl("\nl: 456") == 456, "get_cl(\"456\") returned %d, instead of 456", get_cl("\nl: 456")); 30 | ck_assert_msg(get_cl("\nl: 789\r\n") == 789, "get_cl(\"789\") returned %d, instead of 789", get_cl("\nl: 789\r\n")); 31 | } 32 | END_TEST 33 | 34 | START_TEST (test_find_lr_parameter) { 35 | /* failure cases */ 36 | ck_assert_msg(find_lr_parameter("") == 0, "find_lr_parameter(\"\") returned %d, instead of 0", find_lr_parameter("")); 37 | ck_assert_msg(find_lr_parameter("a") == 0, "find_lr_parameter(\"a\") returned %d, instead of 0", find_lr_parameter("a")); 38 | ck_assert_msg(find_lr_parameter(";lr") == 0, "find_lr_parameter(\";lr\") returned %d, instead of 0", find_lr_parameter(";lr")); 39 | ck_assert_msg(find_lr_parameter("\n") == 0, "find_lr_parameter(\"\\n\") returned %d, instead of 0", find_lr_parameter("\n")); 40 | ck_assert_msg(find_lr_parameter("aaa\nbbb") == 0, "find_lr_parameter(\"aaa\\nbbb\") returned %d, instead of 0", find_lr_parameter("aaa\nbbb")); 41 | ck_assert_msg(find_lr_parameter("a\n;lr") == 0, "find_lr_parameter(\"a\n;lr\") returned %d, instead of 0", find_lr_parameter("a\n;lr")); 42 | 43 | /* success cases */ 44 | ck_assert_msg(find_lr_parameter(";lr\n") == 1, "find_lr_parameter(\";lr\n\") returned %d, instead of 1", find_lr_parameter(";lr\n")); 45 | ck_assert_msg(find_lr_parameter("Record-Route: foo;lr\n") == 1, "find_lr_parameter(\"Record-Route: foo;lr\n\") returned %d, instead of 1", find_lr_parameter(";lr\n")); 46 | } 47 | END_TEST 48 | 49 | START_TEST (test_get_cseq) { 50 | /* failure cases */ 51 | ck_assert_msg(get_cseq("") == 0, "get_cseq(\"\") returned %d, instead of 0", find_lr_parameter("")); 52 | ck_assert_msg(get_cseq("foo") == 0, "get_cseq(\"foo\") returned %d, instead of 0", find_lr_parameter("foo")); 53 | ck_assert_msg(get_cseq("Cseq: ") == 0, "get_cseq(\"Cseq: \") returned %d, instead of 0", find_lr_parameter("Cseq: ")); 54 | ck_assert_msg(get_cseq("Cseq: -5") == 0, "get_cseq(\"Cseq: -5\") returned %d, instead of 0", find_lr_parameter("Cseq: -5")); 55 | ck_assert_msg(get_cseq("Cseq: a") == 0, "get_cseq(\"Cseq: a\") returned %d, instead of 0", find_lr_parameter("Cseq: a")); 56 | 57 | /* success cases */ 58 | ck_assert_msg(get_cseq("Cseq: 1") == 1, "get_cseq(\"Cseq: 1\") returned %d, instead of 1", find_lr_parameter("Cseq: 1")); 59 | ck_assert_msg(get_cseq("Cseq: 123456") == 123456, "get_cseq(\"Cseq: 123456\") returned %d, instead of 123456", find_lr_parameter("Cseq: 123456")); 60 | } 61 | END_TEST 62 | 63 | Suite *header_f_suite(void) { 64 | Suite *s = suite_create("Header_f"); 65 | 66 | /* get_cl test case */ 67 | TCase *tc_get_cl = tcase_create("get_cl"); 68 | tcase_add_test(tc_get_cl, test_get_cl); 69 | /* find_lr_parameter test case */ 70 | TCase *tc_find_lr_parameter = tcase_create("find_lr_parameter"); 71 | tcase_add_test(tc_find_lr_parameter, test_find_lr_parameter); 72 | /* get_cseq test case */ 73 | TCase *tc_get_cseq = tcase_create("get_cseq"); 74 | tcase_add_test(tc_get_cseq, test_get_cseq); 75 | 76 | /* add test cases to suite */ 77 | suite_add_tcase(s, tc_get_cl); 78 | suite_add_tcase(s, tc_find_lr_parameter); 79 | suite_add_tcase(s, tc_get_cseq); 80 | 81 | return s; 82 | } 83 | 84 | int main(void) { 85 | int number_failed; 86 | Suite *s = header_f_suite(); 87 | SRunner *sr = srunner_create(s); 88 | srunner_run_all(sr, CK_VERBOSE); 89 | number_failed = srunner_ntests_failed(sr); 90 | srunner_free(sr); 91 | return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 92 | } 93 | 94 | #else /* HAVE_CHECK_H */ 95 | 96 | #include 97 | int main(void) { 98 | printf("check_helper: !!! missing check unit test framework !!!\n"); 99 | return EXIT_FAILURE; 100 | } 101 | 102 | #endif /* HAVE_CHECK_H */ 103 | -------------------------------------------------------------------------------- /tests/check_helper.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2005-2022 Nils Ohlmeier 3 | * 4 | * This file belongs to sipsak, a free sip testing tool. 5 | * 6 | * sipsak is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * sipsak is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | */ 16 | #include "../config.h" 17 | 18 | #include 19 | 20 | #ifdef HAVE_CHECK_H 21 | 22 | #include 23 | #include "../src/helper.h" 24 | 25 | #define RUNNING_CHECK 1 26 | 27 | void shutdown_network() {}; 28 | 29 | int verbose = 99; 30 | 31 | void exit_code(int code, const char *function, const char *reason) { 32 | ck_abort_msg("Unexpected call to exit_code() with code %i at %s: %s", 33 | code, function, reason); 34 | }; 35 | 36 | START_TEST (test_is_number) { 37 | /* failure cases */ 38 | ck_assert_msg(is_number("") == 0, "is_number(\"\") returned %d, instead of 0", is_number("")); 39 | ck_assert_msg(is_number("a") == 0, "is_number(\"a\") returned %d, instead of 0", is_number("a")); 40 | ck_assert_msg(is_number("XYZ") == 0, "is_number(\"XYZ\") returned %d, instead of 0", is_number("XYZ")); 41 | ck_assert_msg(is_number("10i") == 0, "is_number(\"10i\") returned %d, instead of 0", is_number("10i")); 42 | ck_assert_msg(is_number("p01") == 0, "is_number(\"p01\") returned %d, instead of 0", is_number("p01")); 43 | ck_assert_msg(is_number("p2q") == 0, "is_number(\"p2q\") returned %d, instead of 0", is_number("p2q")); 44 | ck_assert_msg(is_number("1b3") == 0, "is_number(\"1b3\") returned %d, instead of 0", is_number("1b3")); 45 | 46 | /* success cases */ 47 | ck_assert_msg(is_number("1") == 1, "is_number(\"1\") returned %d, instead of 1", is_number("1")); 48 | ck_assert_msg(is_number("10") == 1, "is_number(\"10\") returned %d, instead of 1", is_number("10")); 49 | } 50 | END_TEST 51 | 52 | START_TEST (test_str_to_int) { 53 | /* failure because empty */ 54 | ck_assert_msg(str_to_int(0, "") == -2, "str_to_int(0, \"\") returned %d, instead of -2", str_to_int(0, "")); 55 | ck_assert_msg(str_to_int(1, "") == -2, "str_to_int(1, \"\") returned %d, instead of -2", str_to_int(1, "")); 56 | ck_assert_msg(str_to_int(0, " ") == -2, "str_to_int(0, \" \") returned %d, instead of -2", str_to_int(0, " ")); 57 | ck_assert_msg(str_to_int(1, " ") == -2, "str_to_int(1, \" \") returned %d, instead of -2", str_to_int(1, " ")); 58 | ck_assert_msg(str_to_int(0, " ") == -2, "str_to_int(0, \"\\t\") returned %d, instead of -2", str_to_int(0, " ")); 59 | ck_assert_msg(str_to_int(1, " ") == -2, "str_to_int(1, \"\\t\") returned %d, instead of -2", str_to_int(1, " ")); 60 | ck_assert_msg(str_to_int(0, " ") == -2, "str_to_int(0, \" \\t\") returned %d, instead of -2", str_to_int(0, " ")); 61 | ck_assert_msg(str_to_int(1, " ") == -2, "str_to_int(1, \" \\t\") returned %d, instead of -2", str_to_int(1, " ")); 62 | 63 | /* failure because non-int */ 64 | ck_assert_msg(str_to_int(0, "a") == -2, "str_to_int(0, \"a\") returned %d, instead of -2", str_to_int(0, "a")); 65 | ck_assert_msg(str_to_int(1, "a") == -2, "str_to_int(1, \"a\") returned %d, instead of -2", str_to_int(1, "a")); 66 | ck_assert_msg(str_to_int(0, " a") == -2, "str_to_int(0, \" a\") returned %d, instead of -2", str_to_int(0, " a")); 67 | ck_assert_msg(str_to_int(1, " a") == -2, "str_to_int(1, \" a\") returned %d, instead of -2", str_to_int(1, " a")); 68 | ck_assert_msg(str_to_int(0, " a ") == -2, "str_to_int(0, \" a \") returned %d, instead of -2", str_to_int(0, " a ")); 69 | ck_assert_msg(str_to_int(1, " a ") == -2, "str_to_int(1, \" a \") returned %d, instead of -2", str_to_int(1, " a ")); 70 | ck_assert_msg(str_to_int(0, "ABC") == -2, "str_to_int(0, \"ABC\") returned %d, instead of -2", str_to_int(0, "ABC")); 71 | ck_assert_msg(str_to_int(1, "ABC") == -2, "str_to_int(1, \"ABC\") returned %d, instead of -2", str_to_int(1, "ABC")); 72 | ck_assert_msg(str_to_int(0, " ABC") == -2, "str_to_int(0, \" ABC\") returned %d, instead of -2", str_to_int(0, " ABC")); 73 | ck_assert_msg(str_to_int(1, " ABC") == -2, "str_to_int(1, \" ABC\") returned %d, instead of -2", str_to_int(1, " ABC")); 74 | ck_assert_msg(str_to_int(0, " ABC ") == -2, "str_to_int(0, \" ABC\\t\") returned %d, instead of -2", str_to_int(0, " ABC ")); 75 | ck_assert_msg(str_to_int(1, " ABC ") == -2, "str_to_int(1, \" ABC\\t\") returned %d, instead of -2", str_to_int(1, " ABC ")); 76 | 77 | /* success cases */ 78 | ck_assert_msg(str_to_int(0, "1") == 1, "str_to_int(0, \"1\") returned %d, instead of 1", str_to_int(0, "1")); 79 | ck_assert_msg(str_to_int(1, "1") == 1, "str_to_int(1, \"1\") returned %d, instead of 1", str_to_int(1, "1")); 80 | ck_assert_msg(str_to_int(0, "10") == 10, "str_to_int(0, \"10\") returned %d, instead of 10", str_to_int(0, "10")); 81 | ck_assert_msg(str_to_int(1, "10") == 10, "str_to_int(1, \"10\") returned %d, instead of 10", str_to_int(1, "10")); 82 | ck_assert_msg(str_to_int(0, " 10") == 10, "str_to_int(0, \" 10\") returned %d, instead of 10", str_to_int(0, " 10")); 83 | ck_assert_msg(str_to_int(1, " 10") == 10, "str_to_int(1, \" 10\") returned %d, instead of 10", str_to_int(1, " 10")); 84 | ck_assert_msg(str_to_int(0, " 10 ") == 10, "str_to_int(0, \" 10 \") returned %d, instead of 10", str_to_int(0, " 10 ")); 85 | ck_assert_msg(str_to_int(1, " 10 ") == 10, "str_to_int(1, \" 10 \") returned %d, instead of 10", str_to_int(1, " 10 ")); 86 | ck_assert_msg(str_to_int(0, " 10 ") == 10, "str_to_int(0, \"\\t 10 \\t\") returned %d, instead of 10", str_to_int(0, " 10 ")); 87 | ck_assert_msg(str_to_int(1, " 10 ") == 10, "str_to_int(1, \"\\t 10 \\t\") returned %d, instead of 10", str_to_int(1, " 10 ")); 88 | 89 | /* success and failures depending on the mode */ 90 | ck_assert_msg(str_to_int(0, "1 a") == -2, "str_to_int(0, \"1 a\") returned %d, instead of -2", str_to_int(0, "1 a")); 91 | ck_assert_msg(str_to_int(1, "1 a") == 1, "str_to_int(1, \"1 a\") returned %d, instead of 1", str_to_int(1, "1")); 92 | ck_assert_msg(str_to_int(0, "10 B") == -2, "str_to_int(0, \"10\\tB\") returned %d, instead of -2", str_to_int(0, "10 B")); 93 | ck_assert_msg(str_to_int(1, "10 B") == 10, "str_to_int(1, \"10\\tB\") returned %d, instead of 10", str_to_int(1, "10 B")); 94 | ck_assert_msg(str_to_int(0, " 100 ABC ") == -2, "str_to_int(0, \" 100\\tABC \") returned %d, instead of -2", str_to_int(0, " 100 ABC ")); 95 | ck_assert_msg(str_to_int(1, " 100 ABC ") == 100, "str_to_int(1, \" 100\\tABC \") returned %d, instead of 100", str_to_int(1, " 100 ABC ")); 96 | } 97 | END_TEST 98 | 99 | START_TEST (test_is_ip) { 100 | /* failure cases */ 101 | ck_assert_msg(is_ip("") == 0, "is_ip(\"\") returned %d, instead of 0", is_ip("")); 102 | ck_assert_msg(is_ip("0") == 0, "is_ip(\"0\") returned %d, instead of 0", is_ip("0")); 103 | ck_assert_msg(is_ip("100") == 0, "is_ip(\"100\") returned %d, instead of 0", is_ip("100")); 104 | ck_assert_msg(is_ip("1000") == 0, "is_ip(\"1000\") returned %d, instead of 0", is_ip("1000")); 105 | ck_assert_msg(is_ip("1.0") == 0, "is_ip(\"1.0\") returned %d, instead of 0", is_ip("1.0")); 106 | ck_assert_msg(is_ip("1.2.0") == 0, "is_ip(\"1.2.0\") returned %d, instead of 0", is_ip("1.2.0")); 107 | ck_assert_msg(is_ip("1.2.3.4.5") == 0, "is_ip(\"1.2.3.4.5\") returned %d, instead of 0", is_ip("1.2.3.4.5")); 108 | ck_assert_msg(is_ip("1000.0.0.0") == 0, "is_ip(\"1000.0.0.0\") returned %d, instead of 0", is_ip("1000.0.0.0")); 109 | ck_assert_msg(is_ip("0.1000.0.0") == 0, "is_ip(\"0.1000.0.0\") returned %d, instead of 0", is_ip("0.1000.0.0")); 110 | ck_assert_msg(is_ip("0.0.1000.0") == 0, "is_ip(\"0.0.1000.0\") returned %d, instead of 0", is_ip("0.0.1000.0")); 111 | ck_assert_msg(is_ip("0.0.0.1000") == 0, "is_ip(\"0.0.0.1000\") returned %d, instead of 0", is_ip("0.0.0.1000")); 112 | ck_assert_msg(is_ip("1.2.3.") == 0, "is_ip(\"1.2.3.\") returned %d, instead of 0", is_ip("1.2.3.")); 113 | ck_assert_msg(is_ip(".1.2.3") == 0, "is_ip(\".1.2.3\") returned %d, instead of 0", is_ip(".1.2.3")); 114 | ck_assert_msg(is_ip("1..2.3.4") == 0, "is_ip(\"1..2.3.4\") returned %d, instead of 0", is_ip("1..2.3.4")); 115 | ck_assert_msg(is_ip("999.999.999.999") == 0, "is_ip(\"999.999.999.999\") returned %d, instead of 0", is_ip("999.999.999.999")); 116 | 117 | /* success cases */ 118 | ck_assert_msg(is_ip("0.0.0.0") == 1, "is_ip(\"0.0.0.0\") returned %d, instead of 1", is_ip("0.0.0.0")); 119 | ck_assert_msg(is_ip("1.2.3.4") == 1, "is_ip(\"1.2.3.4\") returned %d, instead of 1", is_ip("1.2.3.4")); 120 | ck_assert_msg(is_ip("192.168.1.1") == 1, "is_ip(\"192.168.1.1\") returned %d, instead of 1", is_ip("192.168.1.1")); 121 | ck_assert_msg(is_ip("255.255.255.255") == 1, "is_ip(\"255.255.255.255\") returned %d, instead of 1", is_ip("255.255.255.255")); 122 | } 123 | END_TEST 124 | 125 | START_TEST (test_getaddress) { 126 | unsigned long localaddr; 127 | 128 | /* failure case */ 129 | ck_assert_msg(getaddress("") == 0, "getaddress(\"\") returned %lu, instead of 0", getaddress("")); 130 | 131 | localaddr = htonl(0x7f000001L); 132 | 133 | /* success cases */ 134 | ck_assert_msg(getaddress("127.0.0.1") == localaddr, "getaddress(\"127.0.0.1\") returned %lu, instead of %lu", getaddress("127.0.0.1"), localaddr); 135 | /* this should work also without DNS */ 136 | ck_assert_msg(getaddress("localhost") == localaddr, "getaddress(\"localhost\") returned %lu, instead of %lu", getaddress("localhost"), localaddr); 137 | } 138 | END_TEST 139 | 140 | START_TEST (test_insert_cr) { 141 | char ta[15]; 142 | 143 | memset(ta, '\0', 15); 144 | insert_cr(ta); 145 | ck_assert_msg(memcmp(ta, "\r\n\0\0\0\0\0\0\0\0\0\0\0\0\0", 15) == 0, "insert_cr(\"\") returned '%s', instead of \"\r\n\"", ta); 146 | 147 | memset(ta, '\0', 15); 148 | memcpy(ta, "test", 4); 149 | insert_cr(ta); 150 | ck_assert_msg(memcmp(ta, "test\r\n\0\0\0\0\0\0\0\0\0", 15) == 0, "insert_cr(\"test\") returned '%s', instead of \"test\r\n\"", ta); 151 | 152 | memset(ta, '\0', 15); 153 | memcpy(ta, "test\n", 5); 154 | insert_cr(ta); 155 | ck_assert_msg(memcmp(ta, "test\r\n\r\n\0\0\0\0\0\0\0", 15) == 0, "insert_cr(\"test\\n\") returned '%s', instead of \"test\\r\\n\"", ta); 156 | 157 | memset(ta, '\0', 15); 158 | memcpy(ta, "foo\nbar\n", 8); 159 | insert_cr(ta); 160 | ck_assert_msg(memcmp(ta, "foo\r\nbar\r\n\r\n\0\0\0", 15) == 0, "insert_cr(\"foo\\nbar\\n\") returned '%s', instead of \"foo\\r\\nbar\\r\\n\"", ta); 161 | } 162 | END_TEST 163 | 164 | START_TEST (test_get_fqdn) { 165 | char fqdn[FQDN_SIZE]; 166 | 167 | memset(fqdn, '\0', FQDN_SIZE); 168 | get_fqdn(fqdn, 0, "127.0.0.15"); 169 | ck_assert_msg(memcmp(fqdn, "127.0.0.15\0", 11) == 0, "get_fqdn returned '%s', instead of '127.0.0.15'", fqdn); 170 | 171 | memset(fqdn, '\0', FQDN_SIZE); 172 | get_fqdn(fqdn, 0, "localhost"); 173 | ck_assert_msg(memcmp(fqdn, "localhost\0", 10) == 0, "get_fqdn returned '%s', instead of 'localhost'", fqdn); 174 | 175 | memset(fqdn, '\0', FQDN_SIZE); 176 | get_fqdn(fqdn, 1, "127.0.0.21"); 177 | ck_assert_msg(memcmp(fqdn, "127.0.0.21\0", 11) == 0, "get_fqdn returned '%s', instead of '127.0.0.21'", fqdn); 178 | 179 | memset(fqdn, '\0', FQDN_SIZE); 180 | get_fqdn(fqdn, 1, "localhost"); 181 | ck_assert_msg(memcmp(fqdn, "127.0.0.1\0", 10) == 0, "get_fqdn returned '%s', instead of '127.0.0.1'", fqdn); 182 | 183 | /* this fails on Travis Linux hosts, because their host names have no dots 184 | memset(fqdn, '\0', FQDN_SIZE); 185 | get_fqdn(fqdn, 0, 0); 186 | ck_assert_msg(memcmp(fqdn, "\0\0\0\0\0", 5) != 0, "get_fqdn empty buffer '%s'", fqdn); 187 | fprintf(stderr, "after fqdn test 1\n"); 188 | 189 | memset(fqdn, '\0', FQDN_SIZE); 190 | get_fqdn(fqdn, 1, 0); 191 | ck_assert_msg(memcmp(fqdn, "127.0.0.1\0", 10) == 0, "get_fqdn returned '%s', instead of '127.0.0.1'", fqdn); 192 | fprintf(stderr, "after fqdn test 2\n"); 193 | */ 194 | } 195 | END_TEST 196 | 197 | Suite *helper_suite(void) { 198 | Suite *s = suite_create("Helper"); 199 | 200 | /* is_number test case */ 201 | TCase *tc_is_number = tcase_create("is_number"); 202 | tcase_add_test(tc_is_number, test_is_number); 203 | 204 | /* str_to_int test case */ 205 | TCase *tc_str_to_int = tcase_create("str_to_int"); 206 | tcase_add_test(tc_str_to_int, test_str_to_int); 207 | 208 | /* is_ip test case */ 209 | TCase *tc_is_ip = tcase_create("is_ip"); 210 | tcase_add_test(tc_is_ip, test_is_ip); 211 | 212 | /* getaddress test case */ 213 | TCase *tc_getaddress = tcase_create("getaddress"); 214 | tcase_add_test(tc_getaddress, test_getaddress); 215 | 216 | /* insert_cr test case */ 217 | TCase *tc_insert_cr = tcase_create("insert_cr"); 218 | tcase_add_test(tc_insert_cr, test_insert_cr); 219 | 220 | /* get_fqdn test case */ 221 | TCase *tc_get_fqdn = tcase_create("get_fqdn"); 222 | tcase_add_test(tc_get_fqdn, test_get_fqdn); 223 | 224 | /* add test cases to suite */ 225 | suite_add_tcase(s, tc_is_number); 226 | suite_add_tcase(s, tc_str_to_int); 227 | suite_add_tcase(s, tc_is_ip); 228 | suite_add_tcase(s, tc_getaddress); 229 | suite_add_tcase(s, tc_insert_cr); 230 | suite_add_tcase(s, tc_get_fqdn); 231 | 232 | return s; 233 | } 234 | 235 | int main(void) { 236 | int number_failed; 237 | Suite *s = helper_suite(); 238 | SRunner *sr = srunner_create(s); 239 | srunner_run_all(sr, CK_VERBOSE); 240 | number_failed = srunner_ntests_failed(sr); 241 | srunner_free(sr); 242 | return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 243 | } 244 | 245 | #else /* HAVE_CHECK_H */ 246 | 247 | #include 248 | int main(void) { 249 | printf("check_helper: !!! missing check unit test framework !!!\n"); 250 | return EXIT_FAILURE; 251 | } 252 | 253 | #endif /* HAVE_CHECK_H */ 254 | -------------------------------------------------------------------------------- /tests/check_md5.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2005-2022 Nils Ohlmeier 3 | * 4 | * This file belongs to sipsak, a free sip testing tool. 5 | * 6 | * sipsak is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * sipsak is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | */ 16 | #include "../config.h" 17 | 18 | #include 19 | 20 | #ifdef HAVE_CHECK_H 21 | 22 | #include 23 | #include "../src/md5.h" 24 | 25 | #define RUNNING_CHECK 1 26 | 27 | char md5hex_buf[33]; /* NULed by initialization */ 28 | const char *md5hex(unsigned char res[16]) { 29 | int i; 30 | for (i = 0; i < 16; ++i) { 31 | sprintf(md5hex_buf + 2 * i, "%02hhx", res[i]); 32 | } 33 | return md5hex_buf; 34 | } 35 | 36 | START_TEST (test_md5_empty) { 37 | const char expected[] = "d41d8cd98f00b204e9800998ecf8427e"; 38 | unsigned char res[16]; 39 | MD5_CTX ctx; 40 | 41 | MD5Init(&ctx); 42 | MD5Final(&res[0], &ctx); 43 | 44 | ck_assert_msg( 45 | strcmp(md5hex(res), expected) == 0, 46 | "md5('') returned %s instead of %s", &md5hex_buf[0], expected); 47 | } 48 | END_TEST 49 | 50 | START_TEST (test_md5_quick_brown_fox) { 51 | const char expected[] = "14aa0efdbdac9187f334b9d25ddeaefe"; 52 | unsigned char res[16]; 53 | MD5_CTX ctx; 54 | 55 | MD5Init(&ctx); 56 | MD5Update(&ctx, "The quick brown fox ", 20); 57 | MD5Update(&ctx, "jumped over ", 12); 58 | MD5Update(&ctx, "the \0NUL\n", 9); 59 | //MD5Update(&ctx, "The quick brown fox jumped over the \0NUL\n", 41); 60 | MD5Final(&res[0], &ctx); 61 | 62 | ck_assert_msg( 63 | strcmp(md5hex(res), expected) == 0, 64 | "md5('The quick brown fox jumped over the \\0NUL\\n') " 65 | "returned %s instead of %s", &md5hex_buf[0], expected); 66 | } 67 | END_TEST 68 | 69 | Suite *md5_suite(void) { 70 | Suite *s = suite_create("MD5"); 71 | 72 | TCase *tc_md5_empty = tcase_create("test_md5_empty"); 73 | tcase_add_test(tc_md5_empty, test_md5_empty); 74 | 75 | TCase *tc_md5_quick_brown_fox = tcase_create("test_md5_quick_brown_fox"); 76 | tcase_add_test(tc_md5_quick_brown_fox, test_md5_quick_brown_fox); 77 | 78 | /* add test cases to suite */ 79 | suite_add_tcase(s, tc_md5_empty); 80 | suite_add_tcase(s, tc_md5_quick_brown_fox); 81 | 82 | return s; 83 | } 84 | 85 | int main(void) { 86 | int number_failed; 87 | Suite *s = md5_suite(); 88 | SRunner *sr = srunner_create(s); 89 | srunner_run_all(sr, CK_VERBOSE); 90 | number_failed = srunner_ntests_failed(sr); 91 | srunner_free(sr); 92 | return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 93 | } 94 | 95 | #else /* HAVE_CHECK_H */ 96 | 97 | #include 98 | int main(void) { 99 | printf("check_md5: !!! missing check unit test framework !!!\n"); 100 | return EXIT_FAILURE; 101 | } 102 | 103 | #endif /* HAVE_CHECK_H */ 104 | --------------------------------------------------------------------------------