pax_global_header00006660000000000000000000000064140056275600014517gustar00rootroot0000000000000052 comment=b43968d5e23a3c890e55401cfacfeef00c0d26c4 inadyn-2.8.1/000077500000000000000000000000001400562756000130115ustar00rootroot00000000000000inadyn-2.8.1/.github/000077500000000000000000000000001400562756000143515ustar00rootroot00000000000000inadyn-2.8.1/.github/workflows/000077500000000000000000000000001400562756000164065ustar00rootroot00000000000000inadyn-2.8.1/.github/workflows/build.yml000066400000000000000000000013621400562756000202320ustar00rootroot00000000000000name: build on: push: branches: - master jobs: build: name: Build runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v2 - name: Set up QEMU uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - name: Login to DockerHub uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v2 with: push: true tags: troglobit/inadyn:latest platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/ppc64le inadyn-2.8.1/.gitignore000066400000000000000000000004711400562756000150030ustar00rootroot00000000000000*~ #*# *.o .deps .dirstamp aclocal.m4 ar-lib autom4te.cache compile config.log config.status config.guess config.sub config.h* configure depcomp inadyn.service include/stamp-h1 INSTALL install-sh libtool ltmain.sh missing Makefile Makefile.in plugins/.dirstamp m4/*.m4 src/inadyn /GPATH /GRTAGS /GSYMS /GTAGS /ID inadyn-2.8.1/.travis.yml000066400000000000000000000036561400562756000151340ustar00rootroot00000000000000# Travis CI integration # Defaults to GNU GCC and autotools: ./configure && make && make test language: c # Use docker for quicker builds, it now allows https://docs.travis-ci.com/user/apt/ sudo: false # Test build with both GCC and Clang (LLVM) compiler: - gcc - clang arch: - amd64 - ppc64le env: global: # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created # via the "travis encrypt" command using the project repo's public key - secure: "JFknJb+purjGIPuKNWFBPlsSLX6KohuYmYV4dmisIhjkeFhhXFQNmoabYQ6D+r/mWYPWiNnohoTSyKv8gjj6eC1SbXb+f2dEXHrmAwr36Enbp2tV0XLx7V2KHZzUmKeJxOSwnNUVZxmSvzVbuiDodtU1PJ2YPK0CM0KF/J+wePA=" # Use Ubuntu 18.04 LTS for builds dist: bionic addons: apt: packages: - tree - fakeroot - debhelper - dh-systemd - libconfuse-dev - libgnutls28-dev coverity_scan: project: name: "troglobit/inadyn" description: "Inadyn | Small and Simple DDNS Client" notification_email: troglobit@gmail.com build_command_prepend: "./autogen.sh && PKG_CONFIG_PATH=/tmp/lib/pkgconfig ./configure --enable-openssl" build_command: "make clean all" branch_pattern: dev install: - wget https://github.com/martinh/libconfuse/releases/download/v3.0/confuse-3.0.tar.xz - tar xf confuse-3.0.tar.xz - (cd confuse-3.0 && ./configure --prefix=/tmp --disable-examples && make && make install-strip) script: - ./autogen.sh - PKG_CONFIG_PATH=/tmp/lib/pkgconfig ./configure --prefix= --disable-ssl - make clean - make V=1 -j5 - PKG_CONFIG_PATH=/tmp/lib/pkgconfig ./configure --prefix= - make clean - make V=1 -j5 - PKG_CONFIG_PATH=/tmp/lib/pkgconfig ./configure --prefix= --enable-openssl - make clean - make V=1 -j5 - DESTDIR=/tmp/tok make install-strip - tree /tmp/tok - ldd /tmp/tok/sbin/inadyn - LD_LIBRARY_PATH=/tmp/lib /tmp/tok/sbin/inadyn -h - PKG_CONFIG_PATH=/tmp/lib/pkgconfig make package - cat ../inadyn*.changes inadyn-2.8.1/AUTHORS000066400000000000000000000005171400562756000140640ustar00rootroot00000000000000Main authors ============ Narcis Ilisei - Original author, http://www.inatech.eu/inadyn/ - All versions up to v1.96.2 Joachim Nilsson - https://github.com/troglobit/inadyn - Maintainer since Oct, 2010 Contributors ============ - Steve Horbachuk - Andrey Tikhomirov - Mike Fleetwood - Timur Birsh - Thomas Waldmann - and many more inadyn-2.8.1/CONTRIBUTING.md000066400000000000000000000062251400562756000152470ustar00rootroot00000000000000Contributing to In-a-dyn ======================== Thank you for considering contributing back to [Free Software][1]! There are a few things we would like you to consider when filing an issue or pull request with this project: 1. If you are filing a bug report or feature request Please take the time to check if an issue already has been filed matching your problem 2. What version are you running, have you tried the latest release? UNIX distributions often package and test software for their particular brand. If you are using a pre-packaged version, then please file a bug with that distribution instead. 3. Coding Style Lines are allowed to be longer than 72 characters these days, there is no enforced max. length. > **Tip:** Always submit code that follows the style of surrounding code! The coding style itself is strictly Linux [KNF][], like GIT it is becoming a de facto standard for C programming https://www.kernel.org/doc/Documentation/CodingStyle 4. Logical Change Sets Changes should be broken down into logical units that add a feature or fix a bug. Keep changes separate from each other and do not mix a bug fix with a whitespace cleanup or a new feature addition. This is important not only for readilibity, or for the possibility of maintainers to revert changes, but does also increase your chances of having a change accepted. 5. Commit messages Commit messages exist to track *why* a change was made. Try to be as clear and concise as possible in your commit messages, and always, be proud of your work and set up a proper GIT identity for your commits: git config --global user.name "Jane Doe" git config --global user.email jane.doe@example.com See this helpful guide for how to write simple, readable commit messages, or have at least a look at the below example. http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html Example ------- Example commit message from the [Pro Git][gitbook] online book, notice how `git commit -s` is used to automatically add a `Signed-off-by`: Capitalized, short (50 chars or less) summary More detailed explanatory text, if necessary. Wrap it to about 72 characters or so. In some contexts, the first line is treated as the subject of an email and the rest of the text as the body. The blank line separating the summary from the body is critical (unless you omit the body entirely); tools like rebase can get confused if you run the two together. Write your commit message in the imperative: "Fix bug" and not "Fixed bug" or "Fixes bug." This convention matches up with commit messages generated by commands like git merge and git revert. Further paragraphs come after blank lines. - Bullet points are okay, too - Typically a hyphen or asterisk is used for the bullet, followed by a single space, with blank lines in between, but conventions vary here - Use a hanging indent Signed-off-by: Jane Doe [1]: http://www.gnu.org/philosophy/free-sw.en.html [KNF]: https://en.wikipedia.org/wiki/Kernel_Normal_Form inadyn-2.8.1/COPYING000066400000000000000000000431031400562756000140450ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. inadyn-2.8.1/ChangeLog.md000066400000000000000000000746421400562756000151770ustar00rootroot00000000000000Change Log ========== All notable changes to the project are documented in this file. [v2.8.1][] - 2021-01-31 ----------------------- ### Fixes - Issue #340: the new settings `ttl` and `proxied`, introduced in [v2.8][], were missing from custom provider sections. Found and fixed by André Colomb [v2.8][] - 2021-01-31 --------------------- Improved `--exec SCRIPT` support and massive Cloudflare plugin updates. ### Changes - Issue #306: New keyword `default` to use the built-in In-a-dyn default `checkip-server` in the configuration file - Issue #306: Automatically fall back to use built-in checkip-server if the provider's server fails. Warnings added to log so user can change their preferences - Issue #310: Extended support for external script. By default it runs only on successful DDNS update (`compat` mode). New `event` mode calls the script on any action, with added new environment variables. - Cloudflare plugin, curated by Simon Pilkington: - Increased size of response buffer, JSON reply is quite big and In-a-dyn is used to one-liner replies from most servers - Add `ttl` option, by なつき - Add `proxied` option, by なつき - Use 1.1.1.1 as default checkip server, by なつき - Updated examples for IPv4 and IPv6, by なつき - New multi-arch docker image, by なつき ### Fixes - Issue #309: Do not attempt to `chown(2)` the cache or pidfile dirs, because this may fail and cause In-a-dyn to fail. Users that want to drop-privs must ensure the cache and pidfile directories are writable by the `-p uid:gid` specified - Issue #313: Cloudflare, get zone name from username field in config - Issue #314: twoDNS changed API, drop support and remove custom example - Issue #327: Fix duiadns.net plugin, by Sergey Aleynikov - Issue #328: Fix TLS regression with multiple data packets, by なつき - Issue #329: Fix creation of new Cloudflare record, by なつき - Fix default install prefix, regression introduced in v2.6 [v2.7][] - 2020-03-22 --------------------- ### Changes - Issue #301: Add `broken-rtc = ` .conf file setting, by Vladislav Grishenko - Issue #302: Add common authentication failure error code handling, by Vladislav Grishenko - Issue #308: Improve Dockerfile by using the same commit of the current Dockerfile to to build inadyn. Previously the Dockerfile always pulled the latest git master, by Dominik Courcelles ### Fixes - Fix #300: `--force` option not being recognized, by Eric Sauvageau - Fix #305: Fix hash generation regression in FreeDNS plugin, found and fixed by Eric Sauvageau and Vladislav Grishenko [v2.6][] - 2020-02-22 --------------------- **NOTE:** The `-1, --once` mode has changed semantics, it no longer defaults to forced update, for that you now need `--force` ### Changes - Add support for Cloudflare, by Simon Pilkington and Jo Rhett - Add Yandex PDD (Yandex.Connect) plugin, by Timur Birsh - Add Dockerfile for running In-a-Dyn from an Alpine container, by Jean-Ralph Aviles with fixes by Robin Bürkli and Richard Powell - Drop support for TZO, acqured by Dyn in 2012 and no longer works - Drop support for DtDNS, shut down August 1, 2018 - Drop support for DynSIP, dropped off the Internet in 2014 - Drop support for Zerigo, shut down in 2017 ### Fixes - Fix #222: Simplify `utimensat()` replacement for macOS Sierra - Fix #223: Sync up with accepted Homebrew formula, by Jo Rhett - Fix #231: Update build requirements and recommendations - Fix #233: Fix building with OpenSSL >1.1, by Rosen Penev - Fix #235: dynv6, don't signal error on unchanged address - Fix #239: Boundary check of MAX supported hostname aliases, bumped max aliases from 20 -> 50 per provider - Fix #241: OpenBSD header ordering, tested on OpenBSD 6.1 - Fix #242: Mention libtool requirement when building from GIT - Fix #247: Check if PID is actually running if PID file exists - Fix internal buffer size warnings, found by GCC-9 (freeDNS) - Fix #256: Document how to use Google Domains plugin - Fix #262: Use .com TLD instead of .org for DynDNS, because the latter cannot be resolved in China, by Eric Sauvageau - Fix #268: Set SIGCHLD to SIG_IGN to reap children, by Markus Gothe - Fixes to socket leaks, memory corrupions, buffer overflows and more, found by Coverity Scan - Fix configure script to allow `--prefix=` for install to `/sbin` - Fix #274: D.U.I.A. DNS basic authentication, by Markus Gothe - Fix #276: Change `--once` behavior, now requires `--force` to update - Fix default checkip server for PubYun/3322, bliao.com not working. This patch adds support for the official 3322 checkip server - Fix #277: See #235 but also for IPv4 ... - Fix #297: api.ipify.org default checkip server for custom providers [v2.5][] - 2018-09-30 --------------------- ### Changes - macOS changes by Jo Rhett: - Add linking with `-lresolv` - Use Homebrew's CA trust store - Update REDAME with install help - Add support for selfhost.de DDNS ### Fixes - Fix #211: Only show DDNS server response on successful transaction - Fix #211: Improved error handling in OpenSSL back-end - Fix #214: Add `nochg` to list of good responses for custom providers - Fixes by Eric Sauvageau: - Fix #216: Add DNS lookup exception for `all.dnsomatic.com` - Fix #219: Add DNS lookup exception for `default@tunnelbrooker.net` [v2.4][] - 2018-08-18 --------------------- ### Changes - Add support for Dynu DDNS provider ### Fixes - Add missing defines for `LLONG_MAX` and `LLONG_MIN` on some platforms - Fix #209: Update FreeDNS plugin to use v2 of their API to fetch update key - Fix #210: Use `~/.cache/inadyn` or `~/.inadyn` when running unprivileged [v2.3.1][] - 2018-02-12 ----------------------- This minor bug fix release holds Debian packaging fixes by André Colomb. ### Changes - Make .deb files an official part of releases ### Fixes - Fix installation of `inadyn` in `/usr/sbin` and symlink in `/usr/bin` - Rename debian/inadyn.links to be standards-compliant - Update deprecated build dependency for dh-systemd - Fix lintian warning about unsafe symlinks for build scripts - Version numbers containing a dash are inappropriate for 'native' packages, bump revision instead [v2.3][] - 2018-01-05 --------------------- ### Changes - Distribute `CONTRIBUTING.md` in release tarballs, by André Colomb - Clean up debug messages for HTTPS connections, by André Colomb - New build-depends, `libgnutls28-dev` for Debian/Ubuntu users and GnuTLS >= 3.0 for others, by André Colomb - Issue #192: Add `examples/*.conf` to source distribution, by André Colomb ### Fixes - TCP, not UDP, for `getaddrinfo()` hints + numeric lookups, by André Colomb - Disable SSL for checkip connections to SPDYN service, by André Colomb - Issue #186: Allow IPv6 for HTTP(S) connections, by André Colomb - Issue #189: Ignore premature session termination in GnuTLS, by André Colomb - Issue #193: Fix broken internal links in README.md, by André Colomb [v2.2.1][] - 2017-10-06 ----------------------- ### Fixes - Issue #174: `gnutls.c` missing `stdint.h`, fix for ArchLinux - Issue #179: Update easyDNS plugin to new API, by Nicholas Alipaz [v2.2][] - 2017-08-09 --------------------- ### Changes - Use HTTP by default for DYN.com checkip server, used by many DDNS providers that do not have their own. This change is far more user friendly since you no longer have to explicitly set `checkip-ssl = false` for the most common use-case. - Some DDNS providers have multiple IP addresses registered for the same service, as of this release Inadyn immediately tries to connect to the next listed addresses on connection problems. - Issue #153: Support for custom HTTP User Agent. Useful with providers that require using a specific brower. Set to, e.g. "Mozilla/4.0", or rely on the default "inadyn/VERSION" user agent. - Support for the `%%` format specifier in custom server URL's, as mentioned in issue #152. - Add support for a `.conf` syntax checker: `inadyn --check-config` - Add support for logging to `stderr` when running in foreground or without syslog enabled - Simplified provider name lookup in `.conf` file. Now substring match is used, resulting in support for `provider Dyn { ... }`. - Remove libite dependency by importing all its used files into inadyn. This should ease adoption by distributions and end users. All code is under free licenses: BSD, ISC. - Import Timur's Debian packaging, adding debconf support ### Fixes - Issue #152: Do not attempt to create PID file in oneshot mode (`-1`) - Issue #152: Must URL encode custom server URL's - Issue #170: Use configured `--prefix` not hard coded `/etc/inadyn.conf` - Issue #172: Use separate variable for `--iface` command line option and `.conf` file option [v2.1][] - 2016-12-04 --------------------- ### Changes - Use HTTPS instead of HTTP by default - Support for disabling HTTPS for `checkip-server`, per provider. Idea from Valery Frolov - Add `-I,--ident=NAME` option for syslog+pidfile name - Deprecate `--pidfile=NAME` option in favor of `--ident=NAME` ### Fixes - Issue #150: Custom update URL parser fixes - Issue #151: Support for detecting OpenSSL v1.1 - Issue #144: Clarify use of public vs private IP. It is possible to register private IP addresses in a public DNS - Clarify `--foreground` option in man page - Document minimum required versions of libite and libConfuse - Portability fixes, replace `__progname` with a small function, replace `%m` with `%s` and `strerror(errno)`. [v2.0][] - 2016-09-12 --------------------- New configuration file format, changed command line options, improved HTTPS support using GnuTLS and Open/LibreSSL. Inadyn now comes with certificate validation enabled by default. ### Changes - New configuration file format using [libConfuse][] - Radically simplified command line, a .conf file is now required - Reorganized SSL code, split `ssl.c` into `openssl.c` and `gnutls.c` - Strict HTTPS certificate validation is now default. To disable this use `strict-ssl = false` in the .conf file. - Certificate validation uses trusted CA certificates from the system with fall-backs to certain known locations. To override this default handling a `ca-trust-file = FILE` setting in `inadyn.conf` can be used to provide the path to another CA cert bundle, in PEM format. - Massive overhaul of `inadyn(8)` and `inadyn.conf(5)` man pages - Support for reading address from interface, including IPv6 addresses - Support for calling an external script to get the IP address - Support for multiple users @ same provider, idea from Valery Frolov: provider default@no-ip.com:1 { username = ian password = secret alias = flemming.no-ip.com } provider default@no-ip.com:2 { username = james password = bond alias = spectre.no-ip.com } - Support for ddnss.de and dynv6.com, contributed by Sven Hoefer - Support for spdyn.de, on request from Frank Röhm - Support for strato.com, contributed by Duncan Overbruck - Support for disabling IP address validation: `verify-address = false` - Refactored memory handling and privilige separation to simplify code - Refactored logging and backgrounding to simplify code - Removed old compatibility symlinks and other required GNU specific files, we now distribute and install README.md and ChangeLog.md ### Fixes - Fix issue #61: Add HTTPS certificate validation for OpenSSL/LibreSSL - Fix issue #67: Use GnuTLS native API for HTTPS - Fix DuckDNS: now requires 'www.' prefix in server URL. By Frank Aurich - Fix issue #110: Poodle `SSL_MODE_SEND_FALLBACK_SCSV` not needed - Fix issue #101: Remove support for custom pidfile - Fix issue #102: Relocate cache files `/var/run/inadyn` to `/var/cache/inadyn` - Fix issue #113: `--drop-privs` does not work - Add actual permissions check to `os_check_perms()` - Fix issue #121: Support for fully customizable update URL - Fix issue #122: Only use HTTPS connection for DNS update, not checkip - Fix issue #131: Use FreeDNS' own checkip server instead of DYN.com's - Fix issue #134: Support wildcard cert with GnuTLS backend [1.99.15][] - 2015-09-09 ------------------------ Minor bugfix release. ### Changes - Support for new API at https://tunnelbroker.net, fixes issue #83. Use `default@tunnelbroker.net` to use the DYN.com API to update the IPv4 address for your IPv6-in-IPv4 tunnel. Thanks goes to Horst Venzke @hvenzke for reporting this problem! - The old API for the IPv6-in-IPv4 system `ipv6tb@he.net` is now deprecated. Users should migrate to `default@tunnelbroker.net` - Files generated by the GNU Configure & Build System is now no longer stored in GIT. Instead, users that rely on GIT must run the new `./autogen.sh` script to generate the necessary files (`configure`). ### Fixes - Fix issue #100: regression from [1.99.13][] pidfile is no longer created. Inadyn 1.x semantics incompatible with OpenBSD `pidfile()` that replaced local version in [1.99.14][]. Problem found by David Schury @daersc. - Fix issue #107: If an IP address update fails, e.g. due to temporary connectivity, HTTP transmission problems, etc. then Inadyn now forces an update in the next IP check cycle. (This is the configurable `period` interval in `inadyn.conf`.) Reported by Oliver Graute @redbrain17 and audited by @BulldozerBSG, thanks! - Fix issue #108: Update README with correct alias syntax for Namecheap, issue reported by @quazar0 [1.99.14][] - 2015-07-14 ------------------------ Improved support for configuring custom DDNS providers and support for running in Windows, using Cygwin! ### Changes - New setting `append-myip` which, instead of appending your hostname alias, appends the current IP to the server GET update URL. See [README][README.md] or the man pages for more details. - Prevent Inadyn from bugging out if it cannot write a cache file when the `-o, --once` flag is given. - Inadyn now defaults to a silent build, use V=1 (like Linux) to get a verbose build. Useful for auto-builders etc. - Migrate to [libite][] for functions like `pidfile()`, `strlcpy()` etc. - Add support for , thanks to Thorsten Mühlfelder! - Add support for , thanks to Ionut Slaveanu! - Add Cygwin support for running Inadyn in Windows, thanks to Scott Mann! ### Fixes - Issue #89: Fix Duck DNS support, thanks to Ismani Nieuweboer! - Issue #82: No rule to build target CHANGELOG, regression introduced in [1.99.13][]. - Issue #84: Sanitized default logs by placing conditions for debug logs. Big thanks to Frank Aurich for this work! [1.99.13][] - 2015-02-08 ------------------------ ### Changes - Add support for DDNS, by Justin McManus - Add support for DDNS service, by Andres Gomez - Add support for DDNS, by Denton Gentry - Rename `NEWS.md` to `CHANGELOG.md` and update formatting in an attempt to align with -- this also means using ISO date format, finally! ### Fixes - Fix issue #78: Parsing checkip responses may fail, by Andy Padavan - Fix issue #79: Don't treat inline '#' as comment if not preceeded by space, by Andy Padavan [1.99.12][] - 2014-10-20 ------------------------ ### Changes - Add custom support for , by Terzeus S. Dominguez ### Fixes - Fix cross compilation issues with OpenSSL (depends on libcrypto) - Fix cross compilation issues with `malloc` vs. `rpl_malloc` (removed autoconf check completely) [1.99.11][] - 2014-10-15 ------------------------ ### Changes - Add support for , thanks to Thomas Waldmann - Add support for DynDNS service extension - Add support for , thanks to Andy Padavan - Updated man pages, both `inadyn(8)` and `inadyn.conf(5)` with examples ### Fixes - Fix building on FreeBSD by converting to use GNU Configure & Build system - Fixes to add support for TLS 1.x with SNI, thanks to Thomas Waldmann - SSL mitigation fixes for POODLE [1.99.10][] - 2014-09-13 ------------------------ ### Changes - Refactor string functions `strcat()` and `strcpy()` to use secure OpenBSD replacements `strlcat()` and `strlcpy()` instead. ### Fixes - Fix issue #57: `snprintf()` causes loss of \= from password string - Fix issue #58: Add support for GnuTLS as the default SSL library - Fix bugs found by Coverity Scan - Fix memory leaks found by GLIBC (!) on PowerPC - Fix include order problem with `error.h` [1.99.9][] - 2014-05-21 ----------------------- ### Changes - Support for DDNS provider - Support for DDNS provider ### Fixes - Fix memory leak in new HTTPS support, found by Valgrind - Other misc. Valgrind and Cppcheck fixes [1.99.8][] - 2014-05-20 ----------------------- ### Changes - Support for HTTPS to secure login credentials at DNS update, issue #36 - Support for persistent cache files with new `--cache-dir PATH` - Support for in generic plugin, see [README][README.md] for details - Man page updates [1.99.7][] - 2014-05-14 ----------------------- ### Changes - Support for multiple cache files, one per DDNS provider, issue #35 - Refactor DDNS providers as plugins, issue #30 [1.99.6][] - 2013-12-25 ----------------------- ### Changes - Update documentation for custom servers and add missing compatibility entry for custom servers. ### Fixes - Fix nasty socket leak. [1.99.5][] - 2013-11-27 ----------------------- ### Changes - Support for `--fake-address` on new `SIGUSR1` (forced update) - Support for `SIGUSR2` (check now), - Support for `--startup-delay SEC`, for embedded systems - Man page updates ### Fixes - Many minor bug fixes [1.99.4][] - 2013-08-08 ----------------------- This release fixes a base64 password encoding regression in [1.99.3][] [1.99.3][] - 2013-07-15 [YANKED] -------------------------------- This release adds the ability to specify the cache file and the ability to check the IP of the interface (UNIX only). If no interface is specified, no external IP check is performed. The old `--iface` option has been renamed `--bind`. changeip.com support has been added. Minor bugfixes and code optimizations have been made. ### Changes - Add ability to specify cache file - Add ability to check IP of interface (UNIX only). If interface is specified, no external IP check performed Old `--iface` option renamed to `--bind` - Specify IP address in freedns.afraid.org update request (only autodetect was used) - Add changeip.com support ### Fixes - Minor bugfixes and code optimization [1.99.2][] - 2012-09-07 ----------------------- ### Changes - Get HTTP status description ### Fixes - Fix inability to change update period (broken in 1.99.0) - Fix debug output description [1.99.1][] - 2012-09-01 ----------------------- ### Changes - Make HTTP status code check server-specific - Update maintainer e-mail address [1.99.0][] - 2012-08-17 ----------------------- ### Changes - Merge wl500g patches from : - `120-heipv6tb.patch` adds support for tunnelbroker - `121-hedyndns.patch` adds support for HE dyndns - `210-wildcard.patch` makes wildcard option account specific - For ddns services that have their own checkip service, use it instead of dyndns.org checkip service - Add ability to handle non-fatal temporary errors ("update too often", system error etc.) - Warn if initial DNS request failed - Add dnsexit.com support - Modify http client to parse response for http status code and response body - Remove DynDNS ignored and deprecated parameters (wildcard, mx, backmx, system). Wildcard kept for easydns.com - Report detected IP to sitelutions and dynsip servers (only autodetect was used) - Update TZO support - Check HTTP status code before validating response - Remake zoneedit response validation - Little code cleanup ### Fixes - Fix malformed HTTP request [1.98.1][] - 2011-07-18 ----------------------- ### Changes - Preserve time since last update (forced update counter) and num interations from being reset by `SIGHUP` restart command - Extend `--drop-privs` to support hyphens - Cleanup of inadyn log messages, reformat & clarification ### Fixes - Bug fix segfault at initial DNS lookup - Bug fix `--drop-privs` uid/gid was swapped and a possible buffer overflow - Typo fixes and polish to man pages inadyn(8) and inadyn.conf(5) [1.98.0][] - 2011-02-28 ----------------------- ### Changes - New config file, command line, syntax (still backwards compatible!) - New option `--drop-privs USER[:GROUP]` to support privilege separation - Drop privileges before creating any files - Documentation updates [1.97.4][] - 2010-11-02 ----------------------- ### Changes - Support for dynsip.org by milkfish, from DD-WRT - Add support for sitelutions.com, from inadyn-mt (untested) ### Fixes - Clear DNS cache before calling `getaddrinfo()`, fixes GitHub issue #3 [1.97.3][] - 2010-11-02 ----------------------- ### Changes - Merge wl500g patches from : - `101-http-request.patch`. This cleans up the DDNS server defintions and callbacks, evidently originating from ideas implemented by DD-WRT. - `102-zoneedit.patch`. This fixes issues in what appears to be both request and response formats in ZoneEdit DDNS. Originating from DD-WRT. - `103-tzo.patch`. This patch adds support for tzo.com DDNS serivices. - `110-dnsomatic.patch`. This patch adds support for DNS-O-Matic , an OpenDNS service which can act as a "meta" update to several other DDNS service providers. - `120-heipv6tb.patch`. This patch adds support for Hurricane Electric's http://tunnelbroker.net/ DDNS services . - When starting: always use cache file, if it exists, or seed with DNS lookup ### Fixes - Fix Debian bug #575549: freedns.afraid.org example in `inadyn(8)` is incorrect. [1.97.2][] - 2010-10-30 ----------------------- ### Changes - Replace `gethostbyname()` with `getaddrinfo()` and improve logging at `connect()` ### Fixes - Fix missing man pages from install/uninstall targets - Fix GitHub issue #2: `setsocktopt()` takes pointer to `struct timeval`, not `int` as argument [1.97.1][] - 2010-10-19 ----------------------- ### Changes - Add support for properly restarting inadyn on `SIGHUP` - Remove `INADYN:` prefix in `MODULE_TAG` entirely - messes up syslog output [1.97.0][] - 2010-10-18 ----------------------- - Apply patches by Neufbox4 from : - `100-inadyn-1.96.2.patch`, cache file support - `100-inadyn-1.96.2.patch`, bind interface support - `200-inadyn-1.96.2-64bits-fix.patch` - `300-inadyn-1.96.2-pidfile-and-improve.patch` - New [README][README.md], COPYING and LICENSE file, remove readme.html - Refactor and cleanup Makefile (renamed from makefile) - Add support for `SIGTERM` signal - Relocate include files to include directory - Apply patch for multiple accounts from Christian Eyrich - Remove unused `uint typedef` causing trouble on ARM GCC 4.4.x - Fix missing `strdup()` of input config file and free any preexisting - Make sure `TYPE_TCP` enum relly is 0 on all compilers - Improve error messages using `strerror()` and use `-1` as stale socket, not `0` - Fix nasty socket leak - Merge with inadyn-advanced, : - Add support for 3322.org and easydns.org - Add support for domain wildcarding, `--wildcard` option NOTE: Domain wildcarding is now *disabled* by default - Add support for running an external command hook on IP update, new `--exec` option - Add support for datetime in debug messages - Refactor `DBG_PRINTF((..))` --> `logit(..)` - Update man page `inadyn(8)` with info on `--bind_interface`, `--wildcard`, `--exec` options and support for easydns.org and 3322.org services - Misc fixes and cleanups 1.96.2 - 2007-03-12 ------------------- ### Fixes - If the Dynamic DNS server responds with an error Inadyn will abort. This will prevent further retries with wrong dyndns credentials. - Default port number included in the request, to support the requests via Proxy, to ports different than 80. - Simplified main inadyn update loop function. (there was no bug there) 1.96 - 2005-09-09 ----------------- ### Changes - zoneedit.com supported. - no-ip.com supported. - support for generic DNS services that support HTTP updates ### Fixes - Immediate exit in case of --iterations=1 (not after a sleep period) - Add missing option for specifying the path in the DNS server 1.95 - 2005-07-20 ----------------- ### Changes - UNIX signals supported - inadyn will stop gracefully in case of ALRM, HUP, INT, ... - New dynamic DNS service supported - www.zoneedit.com - Not tested! - Makefile adjusted for Solaris - compilable under Solaris. - Support for generic DYNDNS service that supports update via HTTP with basic authentication not yet fully complete. Not known where might be applicable. 1.90 - 2005-02-24 ----------------- ### Changes - New option `--change_persona uid:gid` - inadyn can switch the user after launch. Typical feature for daemons - Addition to `--ip_server_name` feature, now it has another parameter: the URL to read from the given server name - Reduced some error messages - Manual pages updated. (thanks to Shaul Karl) ### Fixes - Typo fixed (`--ip_server_name` option) 1.86 - 2005-01-30 ----------------- ### Changes - Updated UNIX man pages for inadyn. Even a page for `inadyn.conf`, Thanks to Shaul Karl! - Inadyn doesn't print anything (e.g. ver. number) anymore when goes to background - New config file parser. Accepts ESCAPE character: `\` ### Fixes - Corrected check of the return code from `socket()` call 1.85 - 2005-01-10 ----------------- ### Changes - Config file related enhancements: - Use default location for config file, when no arguments for inadyn - More *NIX like format for the config file. Thanks to Jerome Benoit ### Fixes - When 'iterations' option is specified as being '1', inadyn exits immediately after first update, not after the sleep period as before 1.81 - 2004-11-23 ----------------- ### Changes - No new features, just a better integration with Linux. Reviewed usage of syslog and fork to background in daemon mode, thanks to Shaul Karl. 1.80 - 2004-10-16 ----------------- ### Changes - Optional output to syslog for Linux, should work for all *nix systems - Run in background for Linux, should work for all *nix systems ### Fixes - Minor compile warnings removed 1.70 - 2004-07-05 ----------------- ### Changes - New `--iterations` cmd line option. Now one can run inadyn with only one iteration. Untested. It was a debug option now made accessible via cmd line. It should work. ### Fixes - Custom DNS from dyndns option was not accepted by the cmd line parser. "Copy-paste" error :-( 1.60 - 2004-06-05 ----------------- ### Changes - On users' request the inadyn can read the options from file. 1.51 - 2004-05-03 ----------------- ### Changes - Support for more aliases for DNS service offered by freedns.afraid.org 1.5 - 2004-05-01 ---------------- ### Changes - Support for dynamic DNS service offered by freedns.afraid.org - Support for http proxy - GPL copyright notice added. 1.4 - 2004-03-01 ---------------- ### Changes - Support for custom DNS and static DNS services offered by dyndns.org - Support for forced IP update, so the account will not expire even though the IP never changes 1.35 - 2004-02-04 ----------------- ### Fixes - Multiple aliases are AGAIN supported - In case of error in IP update the OS signal handler is not installed again. 1.34 - 2003-11-06 ----------------- First port to *NIX - Linux running OK as console app. ### TODO - Run as a background daemon in UNIX - Better interface ### Fixes - Various bug fixes. 1.2 - Jun 2003 -------------- Port to pSOS **Note:** no DNS support under pSOS -- hard coded IP addresses of the server. 1.0 - 20013-05-20 ----------------- First stable version. ### Features - DYNDNS client - free - works fine behind a NAT router - runs fine as a service - has a nice log file ### TODO - port to *NIX - port to pSOS [UNRELEASED]: https://github.com/troglobit/inadyn/compare/v2.8.1...HEAD [v2.8.1]: https://github.com/troglobit/inadyn/compare/v2.8...v2.8.1 [v2.8]: https://github.com/troglobit/inadyn/compare/v2.7...v2.8 [v2.7]: https://github.com/troglobit/inadyn/compare/v2.6...v2.7 [v2.6]: https://github.com/troglobit/inadyn/compare/v2.5...v2.6 [v2.5]: https://github.com/troglobit/inadyn/compare/v2.4...v2.5 [v2.4]: https://github.com/troglobit/inadyn/compare/v2.3.1...v2.4 [v2.3.1]: https://github.com/troglobit/inadyn/compare/v2.3...v2.3.1 [v2.3]: https://github.com/troglobit/inadyn/compare/v2.2.1...v2.3 [v2.2.1]: https://github.com/troglobit/inadyn/compare/v2.2...v2.2.1 [v2.2]: https://github.com/troglobit/inadyn/compare/v2.1...v2.2 [v2.1]: https://github.com/troglobit/inadyn/compare/v2.0...v2.1 [v2.0]: https://github.com/troglobit/inadyn/compare/1.99.15...v2.0 [1.99.15]: https://github.com/troglobit/inadyn/compare/1.99.14...1.99.15 [1.99.14]: https://github.com/troglobit/inadyn/compare/1.99.13...1.99.14 [1.99.13]: https://github.com/troglobit/inadyn/compare/1.99.12...1.99.13 [1.99.12]: https://github.com/troglobit/inadyn/compare/1.99.11...1.99.12 [1.99.11]: https://github.com/troglobit/inadyn/compare/1.99.10...1.99.11 [1.99.10]: https://github.com/troglobit/inadyn/compare/1.99.9...1.99.10 [1.99.9]: https://github.com/troglobit/inadyn/compare/1.99.8...1.99.9 [1.99.8]: https://github.com/troglobit/inadyn/compare/1.99.7...1.99.8 [1.99.7]: https://github.com/troglobit/inadyn/compare/1.99.6...1.99.7 [1.99.6]: https://github.com/troglobit/inadyn/compare/1.99.5...1.99.6 [1.99.5]: https://github.com/troglobit/inadyn/compare/1.99.4...1.99.5 [1.99.4]: https://github.com/troglobit/inadyn/compare/1.99.3...1.99.4 [1.99.3]: https://github.com/troglobit/inadyn/compare/1.99.2...1.99.3 [1.99.1]: https://github.com/troglobit/inadyn/compare/1.99.1...1.99.2 [1.99.1]: https://github.com/troglobit/inadyn/compare/1.99.0...1.99.1 [1.99.0]: https://github.com/troglobit/inadyn/compare/1.98.1...1.99.0 [1.98.1]: https://github.com/troglobit/inadyn/compare/1.98.0...1.98.1 [1.98.0]: https://github.com/troglobit/inadyn/compare/1.97.4...1.98.0 [1.97.4]: https://github.com/troglobit/inadyn/compare/1.97.3...1.97.4 [1.97.3]: https://github.com/troglobit/inadyn/compare/1.97.2...1.97.3 [1.97.2]: https://github.com/troglobit/inadyn/compare/1.97.1...1.97.2 [1.97.1]: https://github.com/troglobit/inadyn/compare/1.97.0...1.97.1 [1.97.0]: https://github.com/troglobit/inadyn/compare/1.96.2...1.97.0 [libite]: https://github.com/troglobit/libite [README.md]: https://github.com/troglobit/inadyn/blob/master/README.md [libConfuse]: https://github.com/martinh/libconfuse inadyn-2.8.1/Dockerfile000066400000000000000000000010351400562756000150020ustar00rootroot00000000000000FROM alpine:latest RUN apk --no-cache add --virtual .build-dependencies \ autoconf \ automake \ confuse-dev \ gcc \ gnutls-dev \ libc-dev \ libtool \ make WORKDIR /root COPY . ./ RUN ./autogen.sh && ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var && make install FROM alpine:latest RUN apk --no-cache add \ ca-certificates \ confuse \ gnutls COPY --from=0 /usr/sbin/inadyn /usr/sbin/inadyn COPY --from=0 /usr/share/doc/inadyn /usr/share/doc/inadyn ENTRYPOINT ["/usr/sbin/inadyn", "--foreground"] inadyn-2.8.1/HomebrewFormula/000077500000000000000000000000001400562756000161075ustar00rootroot00000000000000inadyn-2.8.1/HomebrewFormula/inadyn.rb000066400000000000000000000025231400562756000177200ustar00rootroot00000000000000class Inadyn < Formula desc "Dynamic DNS client with IPv4, IPv6, and SSL/TLS support" homepage "http://troglobit.com/projects/inadyn/" url "https://github.com/troglobit/inadyn/releases/download/v2.5/inadyn-2.5.tar.gz" sha256 "f7faf0be4f0b4bfa1acc811189a9ed0a58bc367e48ea31c283920a2ef27cdc40" version "2.5" head do url "https://github.com/troglobit/inadyn.git" end depends_on "autoconf" => :build depends_on "automake" => :build depends_on "cmake" => :build depends_on "libtool" => :build depends_on "confuse" depends_on "gnutls" depends_on "pkg-config" # Fix for Sierra with v2.5, remove in next version patch do url "https://github.com/troglobit/inadyn/commit/57bdcc0321b49ee68397c70140d9895655edb06f.diff?full_index=1" sha256 "6d24c3822e7017a471583f5424421d83e6e426b464ca7521db943ecec580eea5" end def install mkdir_p buildpath/"inadyn/m4" system "autoreconf", "-vif" system "./configure", "--disable-dependency-tracking", "--disable-silent-rules", "--prefix=#{prefix}", "--sysconfdir=#{etc}", "--localstatedir=#{var}" system "make", "install" end test do system "#{sbin}/inadyn", "--check-config", "--config=#{HOMEBREW_PREFIX}/share/doc/inadyn/examples/inadyn.conf" end end inadyn-2.8.1/Makefile.am000066400000000000000000000034411400562756000150470ustar00rootroot00000000000000ACLOCAL_AMFLAGS = -I m4 DISTCHECK_CONFIGURE_FLAGS = --with-systemd=$$dc_install_base/$(systemd) SUBDIRS = src include man examples doc_DATA = README.md COPYING ChangeLog.md EXTRA_DIST = README.md ChangeLog.md CONTRIBUTING.md DISTCLEANFILES = *~ DEADJOE semantic.cache *.gdb *.elf core core.* *.d if HAVE_SYSTEMD systemd_DATA = inadyn.service endif ## Check if tagged in git release-hook: @if [ ! `git tag | grep $(PACKAGE_VERSION)` ]; then \ echo; \ printf "\e[1m\e[41mCannot find release tag $(PACKAGE_VERSION)\e[0m\n"; \ printf "\e[1m\e[5mDo release anyway?\e[0m "; read yorn; \ if [ "$$yorn" != "y" -a "$$yorn" != "Y" ]; then \ printf "OK, aborting release.\n"; \ exit 1; \ fi; \ echo; \ else \ echo; \ printf "\e[1m\e[42mFound GIT release tag $(PACKAGE_VERSION)\e[0m\n"; \ printf "\e[1m\e[44m>>Remember to push tags!\e[0m\n"; \ echo; \ fi # lintian --profile debian -i -I --show-overrides ../$PKG.changes package build-deb: @dpkg-buildpackage -uc -us -B ## Target to run when building a release release: release-hook distcheck package @for file in $(DIST_ARCHIVES); do \ md5sum $$file > ../$$file.md5; \ sha256sum $$file > ../$$file.sha256; \ done @mv $(DIST_ARCHIVES) ../ @echo @echo "Resulting release files:" @echo "=================================================================" @for file in $(DIST_ARCHIVES); do \ printf "%-32s Distribution tarball\n" $$file; \ printf "%-32s " $$file.md5; cat ../$$file.md5 | cut -f1 -d' '; \ printf "%-32s " $$file.sha256; cat ../$$file.sha256 | cut -f1 -d' '; \ done @for file in `cd ..; ls inadyn_$(VERSION)* inadyn-dbg*_$(VERSION)*`; do \ printf "%-32s Debian/Ubuntu package\n" $$file; \ done inadyn-2.8.1/README.md000066400000000000000000000464741400562756000143070ustar00rootroot00000000000000Internet Automated Dynamic DNS Client ===================================== [![License Badge][]][License] [![Travis Status][]][Travis] [![Coverity Status][]][Coverity Scan] The latest release is always available from GitHub at > https://github.com/troglobit/inadyn/releases Table of Contents ----------------- * [Introduction](#introduction) * [Supported Providers](#supported-providers) * [Configuration](#configuration) * [Custom DDNS Providers](#custom-ddns-providers) * [Build & Install](#build--install) * [Building from GIT](#building-from-git) * [Origin & References](#origin--references) Introduction ------------ Inadyn, or In-a-Dyn, is a small and simple Dynamic DNS, [DDNS][], client with HTTPS support. Commonly available in many GNU/Linux distributions, used in off the shelf routers and Internet gateways to automate the task of keeping your Internet name in sync with your public¹ IP address. It can also be used in installations with redundant (backup) connections to the Internet. Most people are unaware they share a pool of Internet addresses with other users of the same Internet Service Provider (ISP). Protocols like DHCP, PPPoE, or PPPoA are used to give you an address and a way to connect to the Internet, but usually not a way for others to connect to you. If you want to run an Internet server on such a connection you risk losing your IP address every time you reconnect, or as in the case of DHCP even when the lease is renegotiated. By using a DDNS client like `inadyn` you can register an Internet name with a DDNS provider, like [FreeDNS](http://freedns.afraid.org). The DDNS client updates your DNS record periodically and/or on demand when your IP address changes. Inadyn can maintain multiple host records with the same IP address, use a combination of a script, the address from an Internet-facing interface, or default to using the IP address change detector of the DDNS provider. __ ¹ Public IP address is the default, private addresses can also be used. Supported Providers ------------------- Some of these services are free of charge for non-commercial use, some take a small fee, but also provide more domains to choose from: * * * * * * , * * * * * * * , parent of * * * * * * * * * * * * , formerly * * * * * DDNS providers not supported natively can be enabled using the generic DDNS plugin. See below for configuration examples. In-A-Dyn defaults to HTTPS, but not all providers may support this, so try disabling SSL for the update (`ssl = false`) or the checkip phase (`checkip-ssl = false`) in the `provider` section, in case you run into problems. *HTTPS is enabled by default* since it protects your credentials from being snooped and reduces the risk of someone hijacking your account. Configuration ------------- In-A-Dyn supports updating several DDNS servers, several accounts even on different DDNS providers. The following `/etc/inadyn.conf` example show how this can be done. To verify your configuration, without starting the daemon, use: inadyn --check-config This looks for the default `.conf` file, to check any file, use: inadyn --check-config -f /path/to/file.conf ### Example # In-A-Dyn v2.0 configuration file format period = 300 user-agent = Mozilla/5.0 # The FreeDNS username must be in lower case # The password (max 16 chars) is case sensitive provider freedns { username = lower-case-username password = case-sensitive-pwd hostname = some.example.com } # We override checkip server with the In-a-dyn built-in 'default', # api.ipify.org, for details on this, see below. provider freemyip { password = YOUR_TOKEN hostname = YOUR_DOMAIN.freemyip.com checkip-server = default } provider dyn { ssl = false username = charlie password = snoopy hostname = { peanuts, woodstock } user-agent = Mozilla/4.0 } # Google Domains - notice use of '@' to update root entry provider domains.google.com { hostname = @.mydomain.com username = your_username password = your_password } provider duckdns.org { username = YOUR_TOKEN password = noPasswordForDuckdns hostname = YOUR_DOMAIN.duckdns.org } # With multiple usernames at the same provider, index with :# provider no-ip.com:1 { username = ian password = secret hostname = flemming.no-ip.com user-agent = inadyn/2.2 } # With multiple usernames at the same provider, index with :# provider no-ip.com:2 { username = james password = bond hostname = spectre.no-ip.com checkip-ssl = false checkip-server = api.ipify.org } # With multiple usernames at the same provider, index with :# provider no-ip.com:3 { username = spaceman password = bowie hostname = spaceman.no-ip.com checkip-command = "/sbin/ifconfig eth0 | grep 'inet6 addr'" } # Note: hostname == update-key from Advanced tab in the Web UI provider tunnelbroker.net { username = futurekid password = dreoadsad/+dsad21321 # update-key-in-advanced-tab hostname = 1234534245321 # tunnel-id } provider dynv6.com { username = your_token password = n/a hostname = { host1.dynv6.net, host2.dynv6.net } } provider cloudxns.net { username = your_api_key password = your_secret_key hostname = yourhost.example.com } provider dnspod.cn { username = your_api_id password = your_api_token hostname = yourhost.example.com } # Create a unique custom API token with the following permissions: # -> Zone.Zone - Read, Zone.DNS - Edit. provider cloudflare.com { username = zone.name password = api_token_important_read_comment hostname = hostname.zone.name ttl = 1 # optional, value of 1 is 'automatic'. proxied = false # optional. } Notice how the config has three different users of the No-IP provider -- this is achieved by appending a `:ID` to the provider name. We also define a custom cache directory, default is to use `/var/cache`. In our case `/mnt` is a system specific persistent store for caching your IP address as reported to each provider. Inadyn use this to ensure you are not locked out of your account for excessive updates, which may happen if your device Internet gateway running inadyn gets stuck in a reboot loop, or similar. However, for the caching mechanism to be 100% foolproof the system clock must be set correctly -- if you have issues with the system clock not being set properly at boot, e.g. pending receipt of an NTP message, use the command line option `--startup-delay=SEC`. To tell `inadyn` it is OK to proceed before the `SEC` timeout, use `SIGUSR2`. The last system defined is the IPv6 service provided by Hurricane Electric. Here `hostname` is set to the tunnel ID and password **must** be the *Update key* found in the *Advanced* configuration tab. Sometimes the default `checkip-server` for a DDNS provider can be very slow to respond, to this end In-a-dyn now support overriding it with a custom one, or a custom command. The easiest way to change it is to set `checkip-server = default`, triggering In-a-dyn to use `api.ipify.org`, which it also use for custom DDNS providers. See the man pages, or the below section, for more information. Some providers require using a specific browser to send updates, this can be worked around using the `user-agent = STRING` setting, as shown above. It is available both on a global and on a per-provider level. **NOTE:** In a multi-user server setup, make sure to chmod your `.conf` to 600 (read-write only by you/root) to protect against other users reading your DDNS server credentials. Custom DDNS Providers --------------------- In addition to the default DDNS providers supported by Inadyn, custom DDNS providers can be defined in the config file. Use `custom {}` in instead of the `provider {}` section used in examples above. In-A-Dyn use HTTP basic authentication (base64 encoded) to communicate username and password to the server. If you do not have a username and/or password, you can leave these fields out. Basic authentication, will still be used in communication with the server, but with empty username and password. A custom DDNS provider can be setup like this: custom example { username = myuser password = mypass checkip-server = checkip.example.com checkip-path = / ddns-server = update.example.com ddns-path = "/update?hostname=" hostname = myhostname.example.net } You can even override existing plugin support for known DDNS providers, e.g., for it can look as follows. Notice how the hostname syntax differs between these two examples. You need to investigate details like this yourself when using the generic/custom DDNS plugin: custom namecheap { username = myuser password = mypass ddns-server = dynamicdns.park-your-domain.com ddns-path = "/update?domain=YOURDOMAIN.TLD&password=mypass&host=" hostname = { "alpha", "beta", "gamma" } } Here three hostnames are updated, one HTTP GET update request for every DDNS provider is performed, for every listed hostname. Some providers, like FreeDNS, support setting up CNAME records (aliases) to reduce the amount of records you need to update. FreeDNS even default to linking multiple records to the same update, which may be very confusing if you want each DNS record to be updated from a unique IP address -- make sure to *check your settings at the DDNS provider*! Your hostname is automatically appended to the end of the `ddns-path`, as is customary, before it is communicated to the server. Username is your Namecheap username, and password would be the one given to you in the Dynamic DNS panel from Namecheap. Here is an alternative config to illustrate how the `hostname` setting works: custom kruskakli { username = myuser password = mypass ddns-server = dynamicdns.park-your-domain.com ddns-path = "/update?password=mypass&domain=" hostname = YOURDOMAIN.TLD } The generic plugin can also be used with providers that require the client's new IP address in the update request. Here is an example of how this can be done if we *pretend* that is not supported by inadyn. The `ddns-path` differs between providers and is something you must figure out. The support pages sometimes list this under an API section, or similar. # This emulates dyndns.org custom dyn { username = DYNUSERNAME password = DYNPASSWORD ddns-server = members.dyndns.org ddns-path = "/nic/update?hostname=%h.dyndns.org&myip=%i" hostname = { YOURHOST, alias } } Here a fully custom `ddns-path` with format specifiers are used, see the `inadyn.conf(5)` man page for details on this. When using the generic plugin you should first inspect the response from the DDNS provider. By default Inadyn looks for a `200 HTTP` response OK code and the strings `"good"`, `"OK"`, `"true"`, or `"updated"` in the HTTP response body. If the DDNS provider returns something else you can add a list of possible `ddns-response = { Arrr, kilroy }`, or just a single `ddns-response = Cool` -- if your provider does give any response then use `ddns-response = ""`. If your DDNS provider does not provide you with a `checkip-server`, you can use other services, like http://ipify.org, which is the default if you do not specify one for your custom provider config: checkip-server = api.ipify.org or even use a script or command: checkip-command = /sbin/ifconfig eth0 | grep 'inet addr' These two settings can also be used in standard `provider{}` sections. **Note:** `hostname` is required, even if everything is encoded in the `ddns-path`! The given hostname is appended to the `ddns-path` used for updates, unless you use `append-myip` in which case your IP address will be appended instead. When using `append-myip` you probably need to encode your DNS hostname in the `ddns-path` instead, as is done in the last example above. Build & Install --------------- ### Debian/Ubuntu curl -sS https://deb.troglobit.com/pubkey.gpg | sudo apt-key add - echo "deb [arch=amd64] https://deb.troglobit.com/debian stable main" | sudo tee /etc/apt/sources.list.d/troglobit.list sudo apt-get update && sudo apt-get install inadyn ### Docker Automatically built images available here: * https://hub.docker.com/r/troglobit/inadyn A Dockerfile is provided to simplify building and running `inadyn`. docker build -t inadyn:latest . docker run --rm -v "$PWD/inadyn.conf:/etc/inadyn.conf" inadyn:latest ### Homebrew (macOS) To run the latest stable version on macOS, type: brew install inadyn To run the latest version from the master branch, install the git tap instead: brew install --HEAD troglobit/inadyn/inadyn Either of these will install all dependencies. ### Building from Source First download the latest official In-A-Dyn release from GitHub: * https://github.com/troglobit/inadyn/releases In-A-Dyn requires a few libraries to build. The build system searches for them, in their required versions, using the `pkg-config` tool: * [libConfuse][] (3.0+) * [LibreSSL][], [OpenSSL][], or [GnuTLS][] They are available from most UNIX distributions as pre-built packages. Make sure to install the `-dev` or `-devel` package of the distribution packages when building Inadyn. On Debian/Ubuntu (derivatives): $ sudo apt install gnutls-dev libconfuse-dev To build you also need a C compiler, the `pkg-config` tool, and make: $ sudo apt install build-essential pkg-config When building with HTTPS (SSL/TLS) support, make sure to also install the `ca-certificates` package on your system, otherwise Inadyn will not be able to validate the DDNS provider's HTTPS certificates. ### Configure & Build The GNU Configure & Build system use `/usr/local` as the default install prefix. In many cases this is useful, but this means the configuration files and cache files will also use that same prefix. Most users have come to expect those files in `/etc/` and `/var/run/` and configure has a few useful options that are recommended to use: $ ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var $ make -j5 $ sudo make install-strip You may want to remove the `--prefix=/usr` option. ### SSL/TLS Support By default inadyn tries to build with GnuTLS for HTTPS support. GnuTLS is the recommended SSL library to use on UNIX distributions which do not provide OpenSSL/LibreSSL as a system library. However, when OpenSSL or LibreSSL is available as a system library, for example in many embedded systems: ./configure --enable-openssl To completely disable inadyn HTTPS support (not recommended!): ./configure --disable-ssl For more details on the OpenSSL and GNU GPL license issue, see: * * ### RedHat, Fedora, CentOS On some systems the default configure installation path, `/usr/local`, is disabled and not searched by tools like `ldconfig` and `pkg-config`. So if configure fails to find the libConfuse libraries, or the `.pc` files, create the file `/etc/ld.so.conf.d/local.conf` with this content: /usr/local/lib update the linker cache: sudo ldconfig -v |egrep libconfuse and run the Inadyn configure script like this: PKG_CONFIG_PATH=/usr/local/lib/pkgconfig ./configure ### Integration with systemd For systemd integration you need to install `pkg-config`, which helps the Inadyn build system figure out the systemd paths. When installed simply call `systemctl` to enable and start `inadyn`: $ sudo systemctl enable inadyn.service $ sudo systemctl start inadyn.service Check that it started properly by inspecting the system log, or: $ sudo systemctl status inadyn.service Building from GIT ----------------- If you want to contribute, or simply just try out the latest but unreleased features, then you need to know a few things about the [GNU build system][buildsystem]: - `configure.ac` and a per-directory `Makefile.am` are key files - `configure` and `Makefile.in` are generated from `autogen.sh`, they are not stored in GIT but automatically generated for the release tarballs - `Makefile` is generated by `configure` script To build from GIT; clone the repository and run the `autogen.sh` script. This requires the GNU tools `automake`, `autoconf` and `libtool` to be installed on your system. Released tarballs do not require these tools. $ sudo apt install git automake autoconf Then you can clone the repository and create the `configure` script, which is not part of the GIT repo: git clone https://github.com/troglobit/inadyn.git cd inadyn/ ./autogen.sh ./configure && make Building from GIT requires, at least, the previously mentioned library dependencies. GIT sources are a moving target and are not recommended for production systems, unless you know what you are doing! Origin & References ------------------- This is the continuation of Narcis Ilisei's [original][] INADYN. Now maintained by [Joachim Nilsson][]. Please file bug reports, or send pull requests for bug fixes and proposed extensions at [GitHub][]. [original]: http://www.inatech.eu/inadyn/ [DDNS]: http://en.wikipedia.org/wiki/Dynamic_DNS [tunnelbroker]: https://tunnelbroker.net/ [Christian Eyrich]: http://eyrich-net.org/programmiertes.html [Joachim Nilsson]: http://troglobit.com [libConfuse]: https://github.com/martinh/libconfuse [LibreSSL]: http://www.libressl.org/ [OpenSSL]: https://www.openssl.org/ [GnuTLS]: http://www.gnutls.org/ [GitHub]: https://github.com/troglobit/inadyn [buildsystem]: https://airs.com/ian/configure/ [License]: https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html [License Badge]: https://img.shields.io/badge/License-GPL%20v2-blue.svg [Travis]: https://travis-ci.org/troglobit/inadyn [Travis Status]: https://travis-ci.org/troglobit/inadyn.png?branch=master [Coverity Scan]: https://scan.coverity.com/projects/2981 [Coverity Status]: https://scan.coverity.com/projects/2981/badge.svg inadyn-2.8.1/autogen.sh000077500000000000000000000000671400562756000150150ustar00rootroot00000000000000#!/bin/sh mkdir -p m4 autoreconf -W portability -vifm inadyn-2.8.1/configure.ac000066400000000000000000000165451400562756000153120ustar00rootroot00000000000000AC_PREREQ(2.61) AC_INIT([In-a-dyn], [2.8.1], [https://github.com/troglobit/inadyn/issues], [inadyn], [https://troglobit.com/projects/inadyn/]) AC_CONFIG_AUX_DIR(aux) AM_INIT_AUTOMAKE([1.11 foreign dist-xz]) AM_SILENT_RULES([yes]) AC_CONFIG_SRCDIR([src/main.c]) AC_CONFIG_HEADER([include/config.h]) AC_CONFIG_FILES([Makefile inadyn.service src/Makefile include/Makefile man/Makefile examples/Makefile]) AC_CONFIG_MACRO_DIR([m4]) AC_ARG_ENABLE(ssl, [AS_HELP_STRING([--disable-ssl], [Disable HTTPS support, default: enabled])], [ac_enable_ssl="$enableval"], [ac_enable_ssl="yes"] ) AC_ARG_ENABLE(openssl, [AS_HELP_STRING([--enable-openssl], [Use OpenSSL/LibreSSL for HTTPS, default: GnuTLS])], [ac_enable_openssl="$enableval"], [ac_enable_openssl="no"] ) AC_ARG_ENABLE(simulation, [AS_HELP_STRING([--enable-simulation], [Developer simulation mode, do not use!])], [ac_enable_simulation="$enableval"], [ac_enable_simulation="no"] ) AC_ARG_WITH([systemd], [AS_HELP_STRING([--with-systemd=DIR], [Directory for systemd service files])],, [with_systemd=auto] ) # Define necessary build flags AC_GNU_SOURCE AC_USE_SYSTEM_EXTENSIONS # Checks for programs. AC_PROG_CC AC_PROG_CC_C99 AM_PROG_CC_C_O AC_PROG_GCC_TRADITIONAL AC_PROG_INSTALL # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([arpa/inet.h arpa/nameser.h netinet/in.h stdlib.h stdint.h \ string.h sys/ioctl.h sys/socket.h sys/types.h syslog.h unistd.h], [], [], [ #ifdef HAVE_SYS_SOCKET_H #include #endif ]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_C_INLINE AC_TYPE_UINT32_T # Checks for library functions. AC_FUNC_FORK AC_FUNC_SELECT_ARGTYPES AC_CHECK_FUNCS([atexit memset poll socket strerror]) AC_SEARCH_LIBS([dlopen], [dl dld], [], [ AC_MSG_ERROR([unable to find the dlopen() function]) ]) # Check if some func is not in libc AC_CHECK_LIB([util], [pidfile]) # Check for usually missing API's, which we can replace AC_REPLACE_FUNCS([pidfile strlcpy strlcat strtonum utimensat]) AC_CONFIG_LIBOBJ_DIR([lib]) # Needed for the libraries AM_PROG_AR LT_INIT([disable-shared static]) # Check for required packages PKG_PROG_PKG_CONFIG PKG_CHECK_MODULES([confuse], [libconfuse >= 3.0]) LDFLAGS="$LDFLAGS $confuse_LIBS" CPPFLAGS="$CPPFLAGS $confuse_CFLAGS" AC_CHECK_LIB([confuse], [cfg_init], [], AC_MSG_ERROR([*** Configuration file parser library (libConfuse) not found!])) AC_CHECK_HEADERS([confuse.h], [], AC_MSG_ERROR([*** Cannot find required header files!])) # If HTTPS is enabled we check for either OpenSSL/LibreSSL or GnuTLS libs+headers if test "x$ac_enable_ssl" = "xyes"; then if test "x$ac_enable_openssl" = "xyes"; then ac_enable_gnutls="no" PKG_CHECK_MODULES([OpenSSL], [openssl]) LDFLAGS="$LDFLAGS $OpenSSL_LIBS" CPPFLAGS="$CPPFLAGS $OpenSSL_CFLAGS" AC_CHECK_LIB([crypto], [EVP_EncryptInit], [], AC_MSG_ERROR([*** Crypto library (OpenSSL/LibreSSL) not found!])) AC_CHECK_LIB([ssl], [SSL_library_init], [], AC_CHECK_LIB([ssl], [OPENSSL_init_ssl], [], AC_MSG_ERROR([*** SSL library (OpenSSL/LibreSSL) not found!]))) AC_CHECK_HEADERS([openssl/crypto.h openssl/x509.h openssl/pem.h openssl/ssl.h \ openssl/tls1.h openssl/err.h], [], AC_MSG_ERROR([*** Cannot find required header files!]), [ #include ]) AC_DEFINE([CONFIG_OPENSSL], [], [Enable HTTPS support using OpenSSL/LibreSSL library]) else ac_enable_gnutls="yes" PKG_CHECK_MODULES([GnuTLS], [gnutls >= 3.0]) LDFLAGS="$LDFLAGS $GnuTLS_LIBS" CPPFLAGS="$CPPFLAGS $GnuTLS_CFLAGS" AC_CHECK_LIB([gnutls], [gnutls_init], [], AC_MSG_ERROR([*** SSL library (GnuTLS) not found!])) AC_CHECK_HEADERS([gnutls/gnutls.h gnutls/x509.h], [], AC_MSG_ERROR([*** Cannot find required header files!])) AC_DEFINE([CONFIG_GNUTLS], [], [Enable HTTPS support using GnuTLS library]) fi AC_DEFINE([ENABLE_SSL], [], [Enable HTTPS support]) else ac_enable_gnutls="no" ac_enable_openssl="no" fi # By default we rely on the built-in locations of Open/LibreSSL and GnuTLS, # on error we fall back to these two locations # For more excellent information on the topic, see this blog post # https://www.happyassassin.net/2015/01/12/a-note-about-ssltls-trusted-certificate-stores-and-platforms/ CAFILE1="/etc/ssl/certs/ca-certificates.crt" CAFILE2="/etc/pki/tls/certs/ca-bundle.trust.crt" # Add OS-specific flags case "$host_os" in darwin*) LDFLAGS="$LDFLAGS -lresolv" CAFILE2="/usr/local/etc/openssl/cert.pem" # where Homebrew's libressl places it ;; esac AC_DEFINE_UNQUOTED([CAFILE1], "$CAFILE1", [First fallback location for Open/LibreSSL and GnuTLS trust db]) AC_DEFINE_UNQUOTED([CAFILE2], "$CAFILE2", [Second location for Open/LibreSSL and GnuTLS trust db]) AM_CONDITIONAL([ENABLE_SSL], test "x$ac_enable_ssl" = "xyes") AM_CONDITIONAL([ENABLE_OPENSSL], test "x$ac_enable_openssl" = "xyes") if test "x$ac_enable_simulation" = "xyes"; then AC_DEFINE([ENABLE_SIMULATION], [], [Enable developer-only simulation mode]) fi # Check where to install the systemd .service file AS_IF([test "x$with_systemd" = "xyes" -o "x$with_systemd" = "xauto"], [ def_systemd=$($PKG_CONFIG --variable=systemdsystemunitdir systemd) AS_IF([test "x$def_systemd" = "x"], [AS_IF([test "x$with_systemd" = "xyes"], [AC_MSG_ERROR([systemd support requested but pkg-config unable to query systemd package])]) with_systemd=no], [with_systemd="$def_systemd"])] ) AS_IF([test "x$with_systemd" != "xno"], [AC_SUBST([systemddir], [$with_systemd])]) AM_CONDITIONAL([HAVE_SYSTEMD], [test "x$with_systemd" != "xno"]) # Expand $sbindir early, into $SBINDIR, for systemd unit file # NOTE: This does *not* take prefix/exec_prefix override at "make # install" into account, unfortunately. test "x$prefix" = xNONE && prefix=$ac_default_prefix test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' SYSCONFDIR=`eval echo $sysconfdir` SYSCONFDIR=`eval echo $SYSCONFDIR` AC_SUBST(SYSCONFDIR) SBINDIR=`eval echo $sbindir` SBINDIR=`eval echo $SBINDIR` AC_SUBST(SBINDIR) # Workaround for as-of-yet unreleased runstatedir support, planned for # autoconf 2.70, which some major distros have backported. AS_IF([test -z "$runstatedir"], runstatedir="$localstatedir/run") AC_SUBST(runstatedir) AC_OUTPUT # Expand directories for configuration summary, unexpanded defaults: # sysconfdir => ${prefix}/etc # runstatedir => ${localstatedir}/run SYSCONFDIR=`eval echo $sysconfdir` RUNSTATEDIR=`eval echo $runstatedir` RUNSTATEDIR=`eval echo $RUNSTATEDIR` CACHEDIR=`eval echo $localstatedir/cache` cat < Thu, 27 Jul 18:10, 2017 inadyn-2.8.1/debian/changelog000066400000000000000000000343461400562756000161170ustar00rootroot00000000000000inadyn (2.8.1) stable; urgency=medium * Fix warnings for 'ttl' and 'proxied' settings missing in custom provider sections. Found and fixed by André Colomb -- Joachim Wiberg Sun, 31 Jan 2021 23:29:17 +0100 inadyn (2.8) stable; urgency=medium * New keyword 'default' for 'checkip-server', uses api.ipify.org * Fallback to api.ipify.org if a provider's 'checkip-server' fails * Extended support for external script, new 'event' mode introduced to allow script to be called for all events * Massive updates to, and related to, Cloudlflare plugin - Increased size of response buffer, JSON reply is quite big and In-a-dyn is used to one-liner replies from most servers - Add 'ttl' option, by なつき - Add 'proxied' option, by なつき - Use 1.1.1.1 as default checkip server, by なつき - Updated examples for IPv4 and IPv6, by なつき -- Joachim Wiberg Sun, 31 Jan 2021 12:49:52 +0100 inadyn (2.7) stable; urgency=medium * New 'broken-rtc = ' setting * New authentication failure handling, improves error reporting * Fix '--force' option not being recognized * Fix hash generation regression in FreeDNS plugin -- Joachim Nilsson Sun, 22 Mar 2020 11:21:30 +0100 inadyn (2.6) stable; urgency=medium * Add support for Cloudflare * Add support for Yandex PDD * Add Dockerfile for running Inadyn in an Alpine container * Dropped support for: TZO, DtDNS, DynSIP, and Zerigo, services offline * Increased number of aliases (hostnames) per provider, 20 -> 50 * Use .com TLD instead of .org for DynDNS, works in mainland China * Multiple fixes to socket leaks, memory corruptions and buffer overflows * Fixed D.U.I.A. DNS basic authentication * Fix default checkip server for PubYun/3322 * Fix Dynv6 (both IPv4 and IPv6) bogus error on successful update * Add missing build-depends for libConfuse-dev * Sync with latest downstream Debian packaging * Behavior change: `--once` now requires `--force` to force an update even if there is no need to update * Change default checkip server for custom providers to api.ipify.org -- Joachim Nilsson Sat, 22 Feb 2020 16:10:34 +0100 inadyn (2.5) unstable; urgency=medium * Add support for selfhost.de DDNS provider * Only show DDNS server response on successful transaction * Add 'nochg' to list of good responses for custom providers * DNS lookup exceptions for dnsomatic.com and tunnelbrooker.net -- Joachim Nilsson Sun, 30 Sep 2018 11:03:53 +0200 inadyn (2.4) unstable; urgency=medium * Add support for Dynu DDNS provider * Fix FreeDNS plugin, failed to update IPv6 records * Use ~/.cache/inadyn or ~/.inadyn when unprivileged -- Joachim Nilsson Sat, 18 Aug 2018 13:29:01 +0200 inadyn (2.3.1) unstable; urgency=medium * Fix installation of program binary in /usr/sbin and symlink in /usr/bin * Rename debian/inadyn.links to be standards-compliant * Update deprecated build dependency for dh-systemd * Fix lintian warning about unsafe symlinks for build scripts. * Version numbers containing a dash are inappropriate for `native' packages, bump revision instead. -- André Colomb Wed, 10 Jan 2018 22:04:10 +0100 inadyn (2.3-1) unstable; urgency=medium * New upstream release, v2.3 - Allow IPv6 for HTTP(S) connections - Ignore premature session termination in GnuTLS, require GnuTLS >=3.0 - Cleanup of debug messages for HTTPS connections - Disable SSL for checkip connectios to SPDYN service * New build-depends: libgnutls28-dev * Remove unnecessary files: docs, inadyn.examples, install, manpages -- Joachim Nilsson Fri, 05 Jan 2018 03:01:54 +0100 inadyn (2.2.1-1) stable; urgency=low * New upstream bug fix release, v2.2.1 - Build fix for ArchLinux, gnutls.c needs stdint.h for intptr_t conversion - Update easyDNS plugin to new API, by Nicholas Alipaz -- Joachim Nilsson Mon, 06 Oct 2017 23:18:00 +0100 inadyn (2.2-1) unstable; urgency=low * New upstream release: - Silent death likely fixed between v1.96.2 and v2.2. Closes: #781898. - HTTPS support added, using GnuTLS. Closes: #411334. - New release. Closes: #846935. * New maintainer (upstream) * Initial debconf support -- Joachim Nilsson Mon, 10 Jul 2017 08:16:00 +0100 inadyn (1.99.9-1) UNRELEASED; urgency=medium * New upstream release: - Error code fixes on exit, closes: #759278. * Packaging fixes: - Fix package description. Closes: #785397. - Add SysV init script. Closes: #781899. -- Timur Birsh Sat, 19 Jul 2014 18:55:35 +0600 inadyn (1.99.4-1) unstable; urgency=low * New upstream release: - Fix basic HTTP authentication. Closes: #718934. -- Timur Birsh Fri, 09 Aug 2013 13:31:20 +0600 inadyn (1.99.3-1) unstable; urgency=low * New upstream release: - new option --cachefile to specify cache file. - new option --bind to set interface to bind to. - old option --iface used to obtain interface IP with no external IP check. * Fix problem with /run/inadyn access when upgrading from 1.96.2-1. Closes: #709391, #711226. * debian/inadyn.ppp.ip-up: - write PID into /tmp/inadyn.pid. * debian/control: - add full list of the supported services to extended description. * debian/inadyn.init: - use log_action_msg() instead of log_success_msg(). - fix lintian warning init.d-script-call-internal-API. * debian/docs: - README renamed to README.md. * debian/rules: - tell 'make' do not hide build info. * Drop debian/patches, merged upstream. * Update debian/inadyn.conf. * Add debian/links: - add symlink for /usr/sbin/inadyn to /usr/bin/inadyn. -- Timur Birsh Fri, 07 Jun 2013 11:40:43 +0600 inadyn (1.98.1+git20130517-2) unstable; urgency=low * debian/inadyn.{init,ppp.ip-up}: - change $INADYN_{USER,GROUP} to $USER and $GROUP. Closes: #708734. * debian/inadyn.ppp.ip-up: - env vars should be checked after sourcing inadyn's defaults file. * debian/inadyn.postinst: - remove accidentally left code snippet. Closes: #708735. * debian/inadyn.init: - do not warn if daemon is disabled in $DEFAULT. User can use PPP ip-up script instead of the daemon. -- Timur Birsh Sat, 18 May 2013 14:16:53 +0600 inadyn (1.98.1+git20130517-1) unstable; urgency=low * New upstream release (Closes: #647703): - network timeout was fixed. Closes: #539240. - use symbolic persona instead of numeric uid/gid. Closes: #355276. - man/inadyn.8: fix typos. Closes: #575549, #627970. * Update source package in accordance with the version 3.0 (quilt). Closes: #664352. * debian/control: - bump Standards-Version to 3.9.4 (no changes needed). - bump debhelper build dependency to 9 (needed by debhelper's override mechanism). - add Vcs-* fields. - add ${misc:Depends} to the binary package dependency. - update package's short description. * Bump debhelper's compatibility level to 9. * debian/rules: use debhelper's override mechanism. * debian/copyright: - update according to the new upstream source. - follow DEP5. * Add debian/{manpages,docs,install}. * Update debian/watch with the new URL. * debian/changes: merged upstream. * debian/patches: - 01_uid_tAndGid_t.dpatch, 02_inadyn8ManPage.dpatch: merged upstream - remove. * debian/inadyn.conf: use example config from the upstream README. * debian/inadyn.init, debian/inadyn.default: add init script. Closes: #421114. * debian/inadyn.post{inst,rm}: create debian-inadyn user in debian-inadyn group. * Provide dyndns-client virtual package. Closes: #433822. * debian/source/options: use xz compression. -- Timur Birsh Fri, 17 May 2013 16:58:56 +0600 inadyn (1.96.2-1) unstable; urgency=low * New upstream release. * debian/changes: Updating it according to the history specified in readme.html. * debian/control: - bump Standards-Version - 3.8.1. - add Homepage field. - remove patch package build dependency. - bump debhelper version dependency >= 7. - remove fakeroot package build dependency. Closes: #345763. - add dpatch package build dependency. * debian/rules: - bump DH_COMPAT - 5. - move DH_COMPAT declaration to debian/compat file. - move example files declaration to debian/examples. * debian/patches: remove patch - 01_testAndCreateOrigTarBall.dpatch: creating orig tarball not necessary. * debian/watch: fix watch URL. Closes: #456473. * debian/copyright: - add me as maintainer. - update FSF address in license text. - add src/base64utils.c and src/base64.h files licence. * New maintainer. Closes: #514769 (ITA). -- Timur Birsh Tue, 16 Jun 2009 10:43:37 +0600 inadyn (1.96-1) unstable; urgency=low * New upstream release. Closes: #255606, src/os_unix.c:71: error: duplicate case value. * debian/changes: Updating it according to the history specifyed in readme.html. * debian/control: Having no-ip.com mentioned in the supported servers. * debian/patches/: + 01_testAndCreateOrigTarBall.dpatch: Also excluding '*/bin/linux/*' and '*/bin/mac/*' from the orig tar ball. + 02_uid_tAndGid_t.dpatch: Updating the line numbers for the patches. + 03_inadyn8ManPage.dpatch: Updated according to upstream changes. * dpatch: Had to build the package where dpatch was not available. Consequently, + The patches were applied manually. + debian/rules: the 2 lines with dpatch were put into comments. + debian/control: /Build-Depends/s/dpatch, // -- Shaul Karl Sun, 13 Nov 2005 07:10:21 -0600 inadyn (1.95-1) unstable; urgency=low * New upstream release. * debian/changes: Updating it according to the history specifyed in readme.html. * initial uploading to the Debian archive. closes: #255606 (ITP). * debian/rules: + %s/makefile.linux/makefile/ due to upstream making a similar change. + install target: using bin/linux/inadyn rather then bin/inadyn. Once again, this is an upstream modification. * debian/patches/: + 02_setUserGroup.dpatch: Removed as it was merged upstream. + 02_uid_tAndGid_t.dpatch: Added to use Unix uid_t and gid_t. + 03_unixSignals.dpatch: Removed since signals handling were added by upstream. + 03_inadyn8ManPage.dpatch: Document the signals being honored explicitly. * debian/control:Standards-Version: Set to 3.6.2. -- Shaul Karl Thu, 4 Aug 2005 15:29:16 +0300 inadyn (1.90-1) unstable; urgency=low * New upstream release. * debian/changes: Updating it according to the history specifyed in readme.html. * initial uploading to the Debian archives. closes: #255606 (ITP). * debian/patches/01_testAndCreateOrigTarBall: Using fakeroot debian/rules clean before dpkg-source. * debian/control:Build-Depends: Replaced unzip with fakeroot because of debian/patches/01_testAndCreateOrigTarBall. * debian/patches/02_manPages.dpatch: Removed as it was merged upstream. * debian/patches/02_setUserGroup.dpatch: Added to modify upstream handling of the setuid and setgid feature. * debian/patches/03_unixSignals.dpatch: Currently only a framework to handle Unix signals. However it wasn't specified in debian/patches/00list because the full details should be worked with the upstream author. * debian/watch: 2s/net\//net\/readme.html / -- Shaul Karl Sun, 27 Feb 2005 12:29:16 +0200 inadyn (1.86-1) unstable; urgency=low * New upstream release. * debian/changes: Updating it according to the history specifyed in readme.html. * debian/inadyn.conf: updating it to reflect the recognision of an escape character. * debian/patches/01_testAndCreateOrigTarBall: upstream no longer ships .exe files in bin/win32 which distribution might be ilegal. * man pages: - rm debian/inadyn.conf.5 bacuase inadyn.conf.5 is provided by the upstream author. - debian/rules: /dh_installman/s/debian\/inadyn.conf.5/man\/inadyn.conf.5/ - debian/patches/02_manPages.dpatch: Making it refelct the possible usage of an escape character in the configuration file. -- Shaul Karl Tue, 1 Feb 2005 01:30:36 +0200 inadyn (1.85-1) unstable; urgency=low * New upstream release. * A new home page, http://inadyn.ina-tech.net. Updating debian/{copyright,control,watch} * debian/changes: Updating it according to the changes specifyed in readme.html. * debian/patches/01_testAndCreateOrigTarBall: using it also to remove the bin directory from the tar ball, partially because it is not clear whether distributing the .exe files from bin/win32 is legal. * man pages: - rm debian/inadyn.8 bacuase inadyn.man is provided by the upstream author. - debian/rules: /dh_installman/s/debian\/inadyn.8/man\/inadyn.man/ - Modifying inadyn.man to be more consistent with readme.html by means of debian/patches/02_manPages.dpatch - Adding a new inadyn.conf.5 man page. * debian/inadyn.conf: An example configuration file, which is now installed from within debian/rules with dh_installexamples * debian/control: Modified the single line synopsis according to suggestions made by lintian. -- Shaul Karl Fri, 28 Jan 2005 00:58:24 +0200 inadyn (1.80-16.october.2004-1) unstable; urgency=low * New upstream release. * debian/changes: Updating it according to the changes specifyed in readme.html. * debian/patches: now only using 01_testAndCreateOrigTarBall. -- Shaul Karl Mon, 18 Oct 2004 11:48:39 +0200 inadyn (1.70-05.july.2004-1) unstable; urgency=low * New upstream release. * debian/changes: Updating it according to the changes specifyed in readme.txt. * debian/patches/01_testAndCreateOrigTarBall.dpatch is now 01. Adding unzip to debian/control:Build-Depends because of it. -- Shaul Karl Sun, 19 Sep 2004 01:15:32 +0300 inadyn (v1.60-5.june.2004-1) unstable; urgency=low * Initial packaging as a deb. -- Shaul Karl Sun, 20 Jun 2004 16:00:03 +0300 inadyn-2.8.1/debian/compat000066400000000000000000000000031400562756000154320ustar00rootroot0000000000000010 inadyn-2.8.1/debian/config000077500000000000000000000013461400562756000154320ustar00rootroot00000000000000#!/bin/sh . /usr/share/debconf/confmodule db_version 2.0 set -e # This conf script is capable of backing up db_capb backup db_title inadyn STATE=1 while [ "$STATE" != 0 -a "$STATE" != 7 ]; do case "$STATE" in 1) db_input critical inadyn/wizard || true ;; 2) db_get inadyn/wizard if [ "$RET" = "false" ]; then # User maintains their own inadyn.conf exit 0 fi ;; 3) db_input critical inadyn/provider || true ;; 4) db_input critical inadyn/username || true ;; 5) db_input critical inadyn/password || true ;; 6) db_input critical inadyn/hostname || true ;; esac if db_go; then STATE=$(($STATE + 1)) else STATE=$(($STATE - 1)) fi done inadyn-2.8.1/debian/control000066400000000000000000000045561400562756000156500ustar00rootroot00000000000000Source: inadyn Section: net Priority: optional Maintainer: Joachim Nilsson Build-Depends: debhelper (>= 10), libgnutls28-dev, libconfuse-dev, pkg-config, systemd Standards-Version: 4.3.0 Homepage: https://troglobit.com/inadyn.html Vcs-Git: git://github.com/troglobit/inadyn.git Vcs-Browser: http://github.com/troglobit/inadyn Package: inadyn Architecture: any Pre-Depends: adduser Depends: debconf (>= 0.2.17), ${shlibs:Depends}, ${misc:Depends} Provides: dyndns-client Description: Internet automated Dynamic DNS client Inadyn is a small and simple Dynamic DNS (DDNS) client with HTTPS support. It automates the task of keeping your Internet name(s) in sync with your public IP address. . Most people are unaware they share a pool of Internet addresses with other customers of the same Internet Service Provider (ISP). Protocols like DHCP, PPPoE, or PPPoA are used to give you an address and a way to connect to the Internet, but usually not a way for others to connect to you. If you want to run an Internet server on such a connection you risk losing your IP address every time you reconnect. . The following DDNS plugins are supported natively, other providers can be set up with a custom DDNS plugin, see inadyn.conf(5) for an example: . * * * * * * , * * * * * * * , parent of * * * * * * * * * * * * , formerly * * * * * . Some of these services are free of charge for non-commercial use, others take a small fee, but also provide more domains to choose from. inadyn-2.8.1/debian/copyright000066400000000000000000000312271400562756000161730ustar00rootroot00000000000000Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: inadyn - Dynamic DNS client with SSL/TLS support Upstream-Contact: Joachim Nilsson Source: http://github.com/troglobit/inadyn Files: * Copyright: 2003-2004 Narcis Ilisei 2006 Steve Horbachuk 2009 Christoph Brill 2008-2020 Joachim Nilsson 2010 Timur Birsh License: GPL-2+ Files: debian/* Copyright: 2004-2005 Shaul Karl 2009-2014 Timur Birsh License: GPL-2+ Files: include/base64.h include/md5.h include/sha1.h Copyright: 2006-2010 Brainspark B.V. License: GPL-2+ Files: include/cache.h Copyright: 2014-2020 Joachim Nilsson License: GPL-2+ Files: include/compat.h Copyright: 2008-2020 Joachim Nilsson License: MIT/X11 (BSD like) Files: include/ddns.h Copyright: 2010-2020 Joachim Nilsson 2006 Steve Horbachuk 2003-2004 Narcis Ilisei License: GPL-2+ Files: include/error.h Copyright: 2010-2020 Joachim Nilsson 2003-2004 Narcis Ilisei License: GPL-2+ Files: include/http.h Copyright: 2010-2020 Joachim Nilsson 2003-2004 Narcis Ilisei License: GPL-2+ Files: include/jsmn.h Copyright: 2010 Serge Zaitsev License: MIT Files: include/json.h Copyright: 2019 Simon Pilkington License: GPL-2+ Files: include/log.h Copyright: 2010-2020 Joachim Nilsson License: GPL-2+ Files: include/os.h Copyright: 2010-2020 Joachim Nilsson 2006 Steve Horbachuk 2003-2004 Narcis Ilisei License: GPL-2+ Files: include/plugin.h Copyright: 2012-2020 Joachim Nilsson License: MIT/X11 (BSD like) Files: include/queue.h Copyright: 1991, 1993 The Regents of the University of California License: BSD-3-clause Files: include/ssl.h Copyright: 2014-2020 Joachim Nilsson License: GPL-2+ Files: include/strdupa.h Copyright: 2009 William Ahern License: MIT/X11 (BSD like) Files: include/tcp.h Copyright: 2010-2020 Joachim Nilsson 2003-2004 Narcis Ilisei License: GPL-2+ Files: include/strdupa.h Copyright: 2009 William Ahern License: Expat Files: lib/pidfile.c Copyright: 1999 The NetBSD Foundation, Inc. License: BSD-2-clause Files: lib/strlcat.c lib/strlcpy.c Copyright: 1998, 2015 Todd C. Miller License: ISC Files: lib/strtonum.c Copyright: 2004 Ted Unangst and Todd Miller License: ISC Files: lib/utimensat.c Copyright: 2017-2020 Joachim Nilsson License: ISC Files: plugins/cloudflare.c Copyright: 2019-2020 Simon Pilkington License: GPL-2+ Files: plugins/cloudxns.c Copyright: 2017 Richard Yu License: GPL-2+ Files: plugins/common.c Copyright: 2010-2020 Joachim Nilsson 2006 Steve Horbachuk 2003-2004 Narcis Ilisei License: GPL-2+ Files: plugins/ddnss.c Copyright: 2016 Sven Hoefer License: GPL-2+ Files: plugins/dhis.c Copyright: 2014-2020 Joachim Nilsson 2011 Bryan Hoover License: GPL-2+ Files: plugins/dnsexit.c Copyright: 2010-2020 Joachim Nilsson 2006 Steve Horbachuk 2003-2004 Narcis Ilisei License: GPL-2+ Files: plugins/dnspod.c Copyright: 2017 Richard Yu License: GPL-2+ Files: plugins/duckdns.c Copyright: 2014 Andy Padavan 2010-2020 Joachim Nilsson License: GPL-2+ Files: plugins/duiadns.c Copyright: 2015 Duiadns, Co. www.duiadns.net License: GPL-2+ Files: plugins/dyndns.c Copyright: 2010-2020 Joachim Nilsson 2006 Steve Horbachuk 2003-2004 Narcis Ilisei License: GPL-2+ Files: plugins/dynv6.c Copyright: 2016 Sven Hoefer 2020 Joachim Nilsson License: GPL-2+ Files: plugins/easydns.c Copyright: 2010-2020 Joachim Nilsson 2006 Steve Horbachuk 2003-2004 Narcis Ilisei License: GPL-2+ Files: plugins/freedns.c Copyright: 2010-2020 Joachim Nilsson 2006 Steve Horbachuk 2003-2004 Narcis Ilisei License: GPL-2+ Files: plugins/freemyip.c Copyright: 2017 Tomasz 'Cadence' Grabowski License: GPL-2+ Files: plugins/generic.c Copyright: 2010-2020 Joachim Nilsson 2006 Steve Horbachuk 2003-2004 Narcis Ilisei License: GPL-2+ Files: plugins/giradns.c Copyright: 2015 Thorsten Mahlfelder License: GPL-2+ Files: plugins/sitelutions.c Copyright: 2010-2020 Joachim Nilsson 2006 Steve Horbachuk 2003-2004 Narcis Ilisei License: GPL-2+ Files: plugins/tunnelbroker.c Copyright: 2010-2020 Joachim Nilsson 2006 Steve Horbachuk 2003-2004 Narcis Ilisei License: GPL-2+ Files: plugins/zoneedit.c Copyright: 2010-2020 Joachim Nilsson 2006 Steve Horbachuk 2003-2004 Narcis Ilisei License: GPL-2+ Files: src/base64.c src/md5.c src/sha1.c Copyright: 2006-2010 Brainspark B.V. License: GPL-2+ Files: src/cache.c Copyright: 2010-2020 Joachim Nilsson 2003-2004 Narcis Ilisei License: GPL-2+ Files: src/conf.c Copyright: 2014-2020 Joachim Nilsson License: ISC Files: src/jsmn.c Copyright: 2010 Serge Zaitsev License: MIT Files: src/ddns.c Copyright: 2010-2020 Joachim Nilsson 2006 Steve Horbachuk 2003-2004 Narcis Ilisei License: GPL-2+ Files: src/error.c Copyright: 2010-2020 Joachim Nilsson 2003-2004 Narcis Ilisei License: GPL-2+ Files: src/gnutls.c Copyright: 2014-2020 Joachim Nilsson License: GPL-2+ Files: src/http.c Copyright: 2010-2020 Joachim Nilsson 2003-2004 Narcis Ilisei License: GPL-2+ Files: src/log.c Copyright: 2010-2020 Joachim Nilsson License: GPL-2+ Files: src/main.c Copyright: 2010-2020 Joachim Nilsson 2003-2004 Narcis Ilisei License: GPL-2+ Files: src/makepath.c Copyright: 2013-2020 Joachim Nilsson License: ISC Files: src/openssl.c Copyright: 2014-2020 Joachim Nilsson License: GPL-2+ Files: src/os.c Copyright: 2010-2020 Joachim Nilsson 2006 Steve Horbachuk 2003-2004 Narcis Ilisei License: GPL-2+ Files: src/plugin.c Copyright: 2012-2020 Joachim Nilsson License: MIT/X11 (BSD like) Files: src/tcp.c Copyright: 2010-2020 Joachim Nilsson 2003-2004 Narcis Ilisei License: GPL-2+ License: GPL-2+ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. . You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. . On Debian systems, the full text of the GNU General Public License version 2 can be found in the file `/usr/share/common-licenses/GPL-2'. License: ISC Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. . THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. License: Expat Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: . The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. . THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. License: BSD-3-clause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. . THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. License: BSD-2-clause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. . THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. inadyn-2.8.1/debian/dirs000066400000000000000000000000211400562756000151100ustar00rootroot00000000000000var/cache/inadyn inadyn-2.8.1/debian/inadyn.default000066400000000000000000000005341400562756000170650ustar00rootroot00000000000000# Please note, /etc/inadyn.conf should be configured first! # Set to "yes" if inadyn should run in daemon mode # If this is changed to "yes", RUN_IPUP must be set to "no". RUN_DAEMON="no" # Set to "yes" if inadyn should be run every time a new ppp connection is # established. This might be useful, if you are using dial-on-demand. RUN_IPUP="no" inadyn-2.8.1/debian/inadyn.init000077500000000000000000000052561400562756000164150ustar00rootroot00000000000000#!/bin/sh ### BEGIN INIT INFO # Provides: inadyn # Required-Start: $network $local_fs $remote_fs $syslog # Required-Stop: $network $local_fs $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: DynDNS client # Description: Register an Internet name with your IP address ### END INIT INFO # Author: Timur Birsh PATH=/sbin:/usr/sbin:/bin:/usr/bin DESC="DynDNS client" NAME=inadyn DAEMON=/usr/sbin/$NAME RUNDIR=/run/$NAME CACHEDIR=/var/cache/$NAME PIDFILE=/$RUNDIR/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME DEFAULT=/etc/default/$NAME [ -x $DAEMON ] || exit 0 [ -r $DEFAULT ] && . $DEFAULT . /lib/lsb/init-functions # Set defaults values if no DEFAULT exist RUN_DAEMON=${RUN_DAEMON:-no} USER=${USER:-debian-inadyn} GROUP=${GROUP:-debian-inadyn} if [ "$RUN_DAEMON" != "yes" ] && [ "$1" != "stop" ]; then log_action_msg "$NAME: Not starting. Disabled in $DEFAULT" exit 0 fi DAEMON_ARGS="--pidfile $PIDFILE \ --background \ --drop-privs $USER:$GROUP" # Create essential dirs and chown, if missing create_dirs() { for dir in $RUNDIR $CACHEDIR; do if [ ! -d $dir ]; then mkdir $dir chmod 0755 $dir chown $USER:$GROUP $dir fi done } do_start() { create_dirs start-stop-daemon --start --quiet --test \ --pidfile $PIDFILE --exec $DAEMON > /dev/null \ || return 1 start-stop-daemon --start --quiet \ --pidfile $PIDFILE --exec $DAEMON -- $DAEMON_ARGS \ || return 2 } do_stop() { start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 \ --pidfile $PIDFILE --name $NAME RETVAL="$?" [ "$RETVAL" = 2 ] && return 2 rm -f $PIDFILE return "$RETVAL" } do_reload() { start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME return 0 } case "$1" in start) log_daemon_msg "Starting $DESC " "$NAME" do_start case "$?" in 0|1) log_end_msg 0 ;; 2) log_end_msg 1 ;; esac ;; stop) log_daemon_msg "Stopping $DESC" "$NAME" do_stop case "$?" in 0|1) log_end_msg 0 ;; 2) log_end_msg 1 ;; esac ;; status) status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? ;; reload|force-reload) log_daemon_msg "Reloading $DESC" "$NAME" do_reload log_end_msg $? ;; restart) log_daemon_msg "Restarting $DESC" "$NAME" do_stop case "$?" in 0|1) do_start case "$?" in 0) log_end_msg 0 ;; 1) log_end_msg 1 ;; # Old process is still running *) log_end_msg 1 ;; # Failed to start esac ;; *) # Failed to stop log_end_msg 1 ;; esac ;; *) echo "Usage: $SCRIPTNAME {start|stop|status|restart|reload|force-reload}" >&2 exit 3 ;; esac : inadyn-2.8.1/debian/inadyn.links000066400000000000000000000000371400562756000165570ustar00rootroot00000000000000usr/sbin/inadyn usr/bin/inadyn inadyn-2.8.1/debian/inadyn.postinst000066400000000000000000000065401400562756000173270ustar00rootroot00000000000000#!/bin/sh . /usr/share/debconf/confmodule db_version 2.0 set -e NAME=inadyn RUNDIR=/run/$NAME CACHEDIR=/var/cache/$NAME CONF=/etc/$NAME.conf if [ "$1" = "configure" ] then # Create debian-inadyn group if it isn't already there if ! getent group debian-inadyn >/dev/null then # Add system group: debian-inadyn addgroup --system debian-inadyn >/dev/null fi # Create debian-inadyn user if it isn't already there if ! getent passwd debian-inadyn >/dev/null then # Add system user: debian-inadyn adduser \ --system \ --ingroup debian-inadyn \ --home $RUNDIR \ --no-create-home \ --gecos "inadyn dyndns client" \ --shell /bin/false \ --disabled-login \ --disabled-password \ debian-inadyn >/dev/null fi db_get inadyn/wizard if [ "$RET" != "false" ] then # Create inadyn.conf if it does not yet exist, or # Recreate if it was created by us if [ ! -f $CONF -o -n "`grep -s "##DEBCONF##" $CONF`" ] then db_get inadyn/provider provider=$RET db_get inadyn/username username=$RET db_get inadyn/password password=$RET db_get inadyn/hostname hostname=$RET cat < $CONF # Inadyn v2.0 configuration file, automatically generated by debconf # Do not edit this file directly unless you select 'Advanced' during # your next invocation of dpkg-reconfigure inadyn # # NOTE: remove this line if you edit the file manually! ##DEBCONF## # # For details on the syntax of this file, see inadyn.conf(5) period = 300 provider $provider { username = $username password = $password hostname = { $hostname } } EOF chown root:debian-inadyn $CONF chmod 640 $CONF fi fi if [ -f $CONF ] then own=`stat --printf="%u" "$CONF" 2>/dev/null` grp=`stat --printf="%g" "$CONF" 2>/dev/null` if [ "$own" = "0" -a "$grp" = "0" ] then if ! dpkg-statoverride --list $CONF >/dev/null 2>&1 then dpkg-statoverride --update --add root debian-inadyn 640 $CONF fi fi fi for item in $CACHEDIR do own=`stat --printf="%u" "$item" 2>/dev/null` grp=`stat --printf="%g" "$item" 2>/dev/null` if [ "$own" = "0" -a "$grp" = "0" ] then if ! dpkg-statoverride --list $item >/dev/null 2>&1 then dpkg-statoverride --update --add \ debian-inadyn debian-inadyn 755 $item fi fi done for item in $CACHEDIR/* do [ "$item" = "$CACHEDIR/*" ] && continue own=`stat --printf="%u" "$item" 2>/dev/null` grp=`stat --printf="%g" "$item" 2>/dev/null` if [ "$own" = "0" -a "$grp" = "0" ] then chown debian-inadyn "$item" chgrp debian-inadyn "$item" fi done if [ -d $RUNDIR ] then for item in $RUNDIR $RUNDIR/* do [ "$item" = "$RUNDIR/*" ] && continue own=`stat --printf="%u" "$item" 2>/dev/null` grp=`stat --printf="%g" "$item" 2>/dev/null` if [ "$own" = "0" -a "$grp" = "0" ] then chown debian-inadyn "$item" chgrp debian-inadyn "$item" fi done fi fi #DEBHELPER# exit 0 inadyn-2.8.1/debian/inadyn.postrm000066400000000000000000000004641400562756000167670ustar00rootroot00000000000000#!/bin/sh set -e NAME=inadyn RUNDIR=/run/$NAME CACHEDIR=/var/cache/$NAME CONF=/etc/$NAME.conf if [ "$1" = "purge" ]; then if [ -d $RUNDIR ]; then rm -rf $RUNDIR fi rm -rf $CACHEDIR for i in $CONF $CACHEDIR; do dpkg-statoverride --remove $i 2>/dev/null || true done fi #DEBHELPER# exit 0 inadyn-2.8.1/debian/inadyn.ppp.ip-up000066400000000000000000000022711400562756000172710ustar00rootroot00000000000000#!/bin/sh # # ip-up script for inadyn # based on script from ddclient package # # These variables are for the use of the scripts run by run-parts # PPP_IFACE="$1" # PPP_TTY="$2" # PPP_SPEED="$3" # PPP_LOCAL="$4" # PPP_REMOTE="$5" # PPP_IPPARAM="$6" # only run inadyn, if it is installed if [ ! -x /usr/bin/inadyn ]; then exit 0 fi # Check, if this script is activated if [ -r /etc/default/inadyn ]; then . /etc/default/inadyn RUN_IPUP=${RUN_IPUP:-no} USER=${USER:-debian-inadyn} GROUP=${GROUP:-debian-inadyn} if [ ! $RUN_IPUP = "yes" ]; then exit 0 fi # Check, if config exist if [ ! -r /etc/inadyn.conf ]; then exit 0 fi # Check, if this is the interface used for DynDNS (there could be other pppds) eval `sed -n 's/^[[:blank:]]*\(iface[[:blank:]]\+[[:alnum:]]\+\)[[:blank:]]*$/\1/p' \ /etc/inadyn.conf | tr -s '[:blank:]' '='` if [ ! "x$iface" = "x$PPP_IFACE" ]; then exit 0 fi else # No configuration defaults file, so do not run exit 0 fi PIDFILE=/tmp/inadyn.pid # Run inadyn /usr/bin/inadyn --config /etc/inadyn.conf --iterations 1 \ --drop-privs $USER:$GROUP --pidfile "$PIDFILE" # Remove pidfile [ -f "$PIDFILE" ] && rm -f "$PIDFILE" inadyn-2.8.1/debian/rules000077500000000000000000000013701400562756000153140ustar00rootroot00000000000000#!/usr/bin/make -f export DH_VERBOSE=1 export DEB_BUILD_MAINT_OPTIONS = hardening=+all export DEB_CFLAGS_MAINT_APPEND = -W -Wall -Wextra -O3 export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed NUMJOBS = $(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) include /usr/share/dpkg/default.mk # provides DEB_VERSION %: dh $@ --with=systemd override_dh_shlibdeps: dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info override_dh_installchangelogs: dh_installchangelogs ChangeLog.md override_dh_auto_install: dh_auto_install rm -f debian/inadyn/usr/share/doc/inadyn/COPYING rm -f debian/inadyn/usr/share/doc/inadyn/ChangeLog.md override_dh_installinit: dh_systemd_enable dh_installinit dh_systemd_start --no-restart-on-upgrade inadyn-2.8.1/debian/source/000077500000000000000000000000001400562756000155335ustar00rootroot00000000000000inadyn-2.8.1/debian/source/format000066400000000000000000000000151400562756000167420ustar00rootroot000000000000003.0 (native) inadyn-2.8.1/debian/source/options000066400000000000000000000000171400562756000171470ustar00rootroot00000000000000compression=xz inadyn-2.8.1/debian/templates000066400000000000000000000031101400562756000161470ustar00rootroot00000000000000Template: inadyn/wizard Type: boolean Default: true Description: Do you want help creating your /etc/inadyn.conf? This configuration wizard can help you create a basic /etc/inadyn.conf which you can later edit. . If you want to update more than one record at the same provider, or configure a custom DDNS provider, edit /etc/inadyn.conf when this wizard has completed. . NOTE: remove the ##DEBCONF## from /etc/inadyn.conf to prevent future upgrades or reinstall of the package to overwrite your changes. Template: inadyn/provider Type: select Choices: Dyn, FreeDNS, Loopia, nsupdate, duckdns, no-ip.com, dynv6.com, tunnelbroker Default: FreeDNS Description: Dynamic DNS provider: This is just a selection of all the DDNS providers Inadyn supports. If you cannot find your provider in this list, select one and then edit the /etc/inadyn.conf file by hand to set up a custom one. . See the man page for inadyn(8) and inadyn.conf(5) for more information. Template: inadyn/username Type: string Description: Your DDNS provider username: Template: inadyn/password Type: password Description: Your DDNS provider password: When Inadyn has been (re)configured the password is removed from the debconf db, but it will be visible from /etc/inadyn.conf for anyone with root access. Template: inadyn/hostname Type: string Description: Your DDNS provider hostname, or similar: For some providers, most notably Tunnelbroker, the hostname must be an 'update-key', or similar, and not the actual hostname. For most use-cases, however, the hostname is something like this: . hostname.provider.tla inadyn-2.8.1/debian/watch000066400000000000000000000002171400562756000152640ustar00rootroot00000000000000version=3 opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/inadyn-$1\.tar\.gz/ \ https://github.com/troglobit/inadyn/tags .*/v?(\d\S*)\.tar\.gz inadyn-2.8.1/examples/000077500000000000000000000000001400562756000146275ustar00rootroot00000000000000inadyn-2.8.1/examples/Makefile.am000066400000000000000000000003711400562756000166640ustar00rootroot00000000000000examplesdir = $(docdir)/examples dist_examples_DATA = \ cloudflare-ipv4-ipv6.conf \ cloudflare-ipv4-only.conf \ cloudflare-ipv6-only.conf \ custom.conf \ duckdns.conf \ dyndns.conf \ freedns.conf \ freemyip.conf \ inadyn.conf \ README.md inadyn-2.8.1/examples/README.md000066400000000000000000000014201400562756000161030ustar00rootroot00000000000000Example /etc/inadyn.conf files ============================== This directory holds a few example configuration files for common DDNS providers. Please feel free to submit pull requests for your examples at GitHub! :) https://gitub.com/troglobit/inadyn Usage ----- Simply copy the desired example to /etc/inadyn.conf, edit it with your hostname, username, and password and then start Inadyn. Example ------- user@example:~$ sudo cp freedns.conf /etc/inadyn.conf user@example:~$ sudo chmod 600 /etc/inadyn.conf user@example:~$ sudo vim /etc/inadyn.conf [Change username, password and hostname] user@example:~$ sudo inadyn user@example:~$ See the the system logfile for progress and the inadyn man page for debugging help, should you run into problems. inadyn-2.8.1/examples/cloudflare-ipv4-ipv6.conf000066400000000000000000000013041400562756000213560ustar00rootroot00000000000000allow-ipv6 = true # ipv4 provider cloudflare.com:1 { checkip-server = 1.1.1.1 checkip-path = /cdn-cgi/trace username = zone.name password = api_token # Create a unique custom api token with the following permissions: Zone.Zone - Read, Zone.DNS - Edit. hostname = hostname.zone.name ttl = 1 # optional, value of 1 is 'automatic'. proxied = false # optional. } # ipv6 provider cloudflare.com:2 { checkip-server = dns64.cloudflare-dns.com checkip-path = /cdn-cgi/trace username = zone.name password = api_token # Use the same api token as above. hostname = hostname.zone.name ttl = 1 # optional, value of 1 is 'automatic'. proxied = false # optional. } inadyn-2.8.1/examples/cloudflare-ipv4-only.conf000066400000000000000000000004511400562756000214550ustar00rootroot00000000000000provider cloudflare.com { username = zone.name password = api_token # Create a unique custom api token with the following permissions: Zone.Zone - Read, Zone.DNS - Edit. hostname = hostname.zone.name ttl = 1 # optional, value of 1 is 'automatic'. proxied = false # optional. } inadyn-2.8.1/examples/cloudflare-ipv6-only.conf000066400000000000000000000006141400562756000214600ustar00rootroot00000000000000allow-ipv6 = true provider cloudflare.com { checkip-server = dns64.cloudflare-dns.com checkip-path = /cdn-cgi/trace username = zone.name password = api_token # Create a unique custom api token with the following permissions: Zone.Zone - Read, Zone.DNS - Edit. hostname = hostname.zone.name ttl = 1 # optional, value of 1 is 'automatic'. proxied = false # optional. } inadyn-2.8.1/examples/custom.conf000066400000000000000000000010401400562756000170030ustar00rootroot00000000000000# Inadyn v2.0 configuration file format iface = wlp3s0 #verify-address = false custom kruskakli { username = myuser password = mypass ssl = true # checkip-command = "/sbin/ifconfig wlp3s0 | grep 'inet addr'" ddns-server = dynamicdns.park-your-domain.com # ddns-path = "/update?password=mypass&domain=" ddns-path = "/update?user=%u&password=%p&domain=%h&myip=%i" # ddns-response = { "hej", "ko", "massa" } ddns-response = "" hostname = YOURDOMAIN.TLD # checkip-server = api.ipify.org } inadyn-2.8.1/examples/duckdns.conf000066400000000000000000000003401400562756000171260ustar00rootroot00000000000000# innadyn v2.0 configuration file format period = 1800 #verify-address = false provider duckdns.org { username = YOUR_TOKEN password = noPasswordForDuckdns hostname = YOUR_DOMAIN.duckdns.org } inadyn-2.8.1/examples/dyndns.conf000066400000000000000000000003441400562756000167760ustar00rootroot00000000000000# Inadyn v2.0 configuration file format period = 300 #verify-address = false provider default@dyndns.org { ssl = true username = user password = secret hostname = example.dyndns.org } inadyn-2.8.1/examples/freedns.conf000066400000000000000000000004341400562756000171250ustar00rootroot00000000000000# Inadyn v2.0 configuration file format period = 300 #verify-address = false provider default@freedns.afraid.org { ssl = true username = user password = secret hostname = coffee.example.org # checkip-server = api.ipify.org } inadyn-2.8.1/examples/freemyip.conf000066400000000000000000000003001400562756000173070ustar00rootroot00000000000000# Inadyn v2.0 configuration file format period = 300 #verify-address = false provider default@freemyip.com { password = token hostname = hostname.freemyip.com } inadyn-2.8.1/examples/inadyn.conf000066400000000000000000000033471400562756000167670ustar00rootroot00000000000000# /etc/inadyn.conf :: v2 configuration file format # # 1. Select a matching DDNS provider to uncomment, this file lists a few # common ones, including a custom one, see inadyn(8) for the full list # # 2. Edit the following options: # - your username at the DDNS provider # - your password at the DDNS provider # - the DNS hostname(s) you want to update # # 3. Ensure to set 600 permissions on this file! # # See inadyn.conf(5) for detailed information on the syntax # How often the IP is checked. The value denotes seconds #period = 300 # Custom HTTP user agent, some DDNS providers require this. # Default is inadyn/VERSION, you rarely need this. #user-agent = Mozilla/4.1 # Set interface to check for IP, default is to ask an external # checkip server -- you rarely need this. #iface = eth1 ### FreeDNS -- https://freedns.afraid.org #provider freedns.afraid.org { # username = # password = # hostname = #} ### Loopia -- https://www.loopia.com #provider loopia { # username = # password = ## wildcard = true # hostname = { , , ... } #} ### DYN.com -- http://www.dyn.com #provider Dyn { # username = # password = # hostname = #} ### FreeMyIP -- https://freemyip.com #provider freemyip.com { # password = # hostname = .freemyip.com #} ### Custom provider example #custom example { # username = # password = # checkip-server = checkip.example.com # checkip-path = / # checkip-ssl = false # ddns-server = update.example.com # ddns-path = "/update?hostname=%h" # ssl = true # hostname = .example.net #} inadyn-2.8.1/inadyn.service.in000066400000000000000000000005361400562756000162660ustar00rootroot00000000000000[Unit] Description=Internet Dynamic DNS Client Documentation=man:inadyn Documentation=man:inadyn.conf Documentation=https://github.com/troglobit/inadyn ConditionPathExists=@SYSCONFDIR@/inadyn.conf After=network-online.target Requires=network-online.target [Service] Type=simple ExecStart=@SBINDIR@/inadyn -n -s [Install] WantedBy=multi-user.target inadyn-2.8.1/include/000077500000000000000000000000001400562756000144345ustar00rootroot00000000000000inadyn-2.8.1/include/Makefile.am000066400000000000000000000003501400562756000164660ustar00rootroot00000000000000inadyndir = ../src noinst_HEADERS = base64.h md5.h sha1.h \ cache.h compat.h config.h.in \ ddns.h error.h http.h \ jsmn.h json.h log.h \ md5.h os.h plugin.h \ queue.h sha1.h ssl.h \ strdupa.h tcp.h inadyn-2.8.1/include/base64.h000066400000000000000000000053561400562756000157020ustar00rootroot00000000000000/** * \file base64.h * * \brief RFC 1521 base64 encoding/decoding * * Copyright (C) 2006-2010, Brainspark B.V. * * This file is part of PolarSSL (http://www.polarssl.org) * Lead Maintainer: Paul Bakker * * All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef BASE64_H #define BASE64_H #include #include #define ERR_BASE64_BUFFER_TOO_SMALL -0x002A /**< Output buffer too small. */ #define ERR_BASE64_INVALID_CHARACTER -0x002C /**< Invalid character in input. */ /** * \brief Encode a buffer into base64 format * * \param dst destination buffer * \param dlen size of the buffer * \param src source buffer * \param slen amount of data to be encoded * * \return 0 if successful, or POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL. * *dlen is always updated to reflect the amount * of data that has (or would have) been written. * * \note Call this function with *dlen = 0 to obtain the * required buffer size in *dlen */ int base64_encode( unsigned char *dst, size_t *dlen, const unsigned char *src, size_t slen ); /** * \brief Decode a base64-formatted buffer * * \param dst destination buffer * \param dlen size of the buffer * \param src source buffer * \param slen amount of data to be decoded * * \return 0 if successful, POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL, or * POLARSSL_ERR_BASE64_INVALID_DATA if the input data is not * correct. *dlen is always updated to reflect the amount * of data that has (or would have) been written. * * \note Call this function with *dlen = 0 to obtain the * required buffer size in *dlen */ int base64_decode( unsigned char *dst, size_t *dlen, const unsigned char *src, size_t slen ); #endif /* base64.h */ inadyn-2.8.1/include/cache.h000066400000000000000000000023751400562756000156570ustar00rootroot00000000000000/* Interface to file chache API * * Copyright (C) 2014-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef INADYN_CACHE_H_ #define INADYN_CACHE_H_ #include "ddns.h" extern char *cache_dir; char *cache_file (char *name, char *buf, size_t len); int read_cache_file (ddns_t *ctx); int write_cache_file (ddns_alias_t *alias); #endif /* INADYN_CACHE_H_ */ /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/include/compat.h000066400000000000000000000057411400562756000160770ustar00rootroot00000000000000/* Collection of frog DNA * * Copyright (c) 2008-2020 Joachim Nilsson * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef INADYN_COMPAT_H_ #define INADYN_COMPAT_H_ #include #include #include #include #include /* MAX(), isset(), setbit(), TRUE, FALSE, et consortes. :-) */ #include #include "strdupa.h" /* From The Practice of Programming, by Kernighan and Pike */ #ifndef NELEMS #define NELEMS(array) (sizeof(array) / sizeof(array[0])) #endif int mkpath (char *dir, mode_t mode); #ifndef pidfile int pidfile (const char *basename); #endif #ifndef strlcpy size_t strlcpy (char *dst, const char *src, size_t siz); #endif #ifndef strlcat size_t strlcat (char *dst, const char *src, size_t siz); #endif #ifndef strtonum long long strtonum (const char *numstr, long long minval, long long maxval, const char **errstrp); #endif /* Convert string to natural number (0-2147483647), returns -1 on error. */ static inline int atonum(const char *str) { int val = -1; const char *errstr; if (str) { val = strtonum(str, 0, INT32_MAX, &errstr); if (errstr) return -1; } return val; } /* Check if a file exists in the file system */ static inline int fexist(char *file) { if (!file) { errno = EINVAL; return 0; /* Doesn't exist ... */ } if (-1 == access(file, F_OK)) return 0; return 1; } /* Validate string, non NULL and not zero length */ static inline int string_valid(const char *s) { return s && strlen(s); } /* Relaxed comparison, e.g., sys_string_match("small", "smaller") => TRUE */ static inline int string_match(const char *a, const char *b) { size_t min = MIN(strlen(a), strlen(b)); return !strncasecmp(a, b, min); } /* Strict comparison, e.g., sys_string_match("small", "smaller") => FALSE */ static inline int string_compare(const char *a, const char *b) { return strlen(a) == strlen(b) && !strcmp(a, b); } #endif /* INADYN_COMPAT_H_ */ inadyn-2.8.1/include/ddns.h000066400000000000000000000164001400562756000155360ustar00rootroot00000000000000/* Interface for main DDNS functions * * Copyright (C) 2003-2004 Narcis Ilisei * Copyright (C) 2006 Steve Horbachuk * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef DDNS_H_ #define DDNS_H_ #include "config.h" #include "compat.h" #include "os.h" #include "error.h" #include "http.h" #include "log.h" #include "plugin.h" #include "queue.h" /* BSD sys/queue.h API */ #define VERSION_STRING PACKAGE_NAME " version " VERSION " -- Dynamic DNS update client." #define DDNS_USER_AGENT "inadyn/" VERSION " " PACKAGE_BUGREPORT /* 2017-01-05: Dyn.com does NOT support HTTPS for checkip */ #define DYNDNS_MY_IP_SERVER "checkip.dyndns.com" #define DYNDNS_MY_CHECKIP_URL "/" #define DYNDNS_MY_IP_SSL DDNS_CHECKIP_SSL_UNSUPPORTED /* * 2020-02-18: ipify.org support HTTPS and should be default for new * providers, unless the provider has its own checkip infrastructure. */ #define DDNS_MY_IP_SERVER "api.ipify.org" #define DDNS_MY_CHECKIP_URL "/" #define DDNS_MY_IP_SSL DDNS_CHECKIP_SSL_SUPPORTED /* Some default settings */ #define DDNS_DEFAULT_STARTUP_SLEEP 0 /* sec */ #define DDNS_DEFAULT_PERIOD 120 /* sec */ #define DDNS_MIN_PERIOD 30 /* sec */ #define DDNS_MAX_PERIOD (10 * 24 * 3600) /* 10 days in sec */ #define DDNS_ERROR_UPDATE_PERIOD 600 /* 10 min */ #define DDNS_FORCED_UPDATE_PERIOD (30 * 24 * 3600) /* 30 days in sec */ #define DDNS_DEFAULT_CMD_CHECK_PERIOD 1 /* sec */ #define DDNS_DEFAULT_ITERATIONS 0 /* Forever */ #define DDNS_HTTP_RESPONSE_BUFFER_SIZE (BUFSIZ < 8192 ? 8192 : BUFSIZ) /* at least 8 Kib */ #define DDNS_HTTP_REQUEST_BUFFER_SIZE 2500 /* Bytes */ #define DDNS_MAX_ALIAS_NUMBER 50 /* maximum number of aliases per server that can be maintained */ #define DDNS_MAX_SERVER_NUMBER 5 /* maximum number of servers that can be maintained */ /* SSL support status in plugin definition */ #define DDNS_CHECKIP_SSL_UNSUPPORTED -1 /* HTTPS not supported by checkip-server (default) */ #define DDNS_CHECKIP_SSL_SUPPORTED 1 /* HTTPS supported by checkip-server */ #define DDNS_CHECKIP_SSL_REQUIRED 3 /* HTTPS required for checkip-server */ /* local configs */ #define USERNAME_LEN 128 /* chars */ #define PASSWORD_LEN 256 /* chars */ #define SERVER_NAME_LEN 256 /* chars */ #define SERVER_URL_LEN 256 /* chars */ #ifdef INET6_ADDRSTRLEN # define MAX_ADDRESS_LEN INET6_ADDRSTRLEN #else # define MAX_ADDRESS_LEN 46 #endif #define MAX_NUM_RESPONSES 5 #define MAX_RESPONSE_LEN 32 typedef enum { NO_CMD = 0, CMD_STOP, CMD_RESTART, CMD_FORCED_UPDATE, CMD_CHECK_NOW, } ddns_cmd_t; typedef enum { EXEC_MODE_COMPAT, EXEC_MODE_EVENT } ddns_exec_mode_t; typedef struct { char username[USERNAME_LEN]; char password[PASSWORD_LEN]; char *encoded_password; int size; int encoded; } ddns_creds_t; /* Server name and port */ typedef struct { char name[SERVER_NAME_LEN]; int port; } ddns_name_t; typedef struct { int ip_has_changed; char address[MAX_ADDRESS_LEN]; char name[SERVER_NAME_LEN]; int update_required; time_t last_update; } ddns_alias_t; typedef struct di { LIST_ENTRY(di) link; int id; ddns_creds_t creds; ddns_system_t *system; /* Per provider custom user agent */ char *user_agent; /* Address of DDNS update service */ ddns_name_t server_name; char server_url[SERVER_URL_LEN]; http_t server; /* Possble "OK" responses from DDNS provider */ char server_response[MAX_NUM_RESPONSES][MAX_RESPONSE_LEN]; size_t server_response_num; /* Address of "What's my IP" checker */ ddns_name_t checkip_name; char checkip_url[SERVER_URL_LEN]; int checkip_ssl; /* checkip server ssl mode */ http_t checkip; /* Shell command for "What's my IP" checker */ char *checkip_cmd; /* Optional local proxy server for this DDNS provider */ tcp_proxy_type_t proxy_type; ddns_name_t proxy_name; /* Your aliases/names to update */ ddns_alias_t alias[DDNS_MAX_ALIAS_NUMBER]; size_t alias_count; /* Use wildcard, *.foo.bar */ int wildcard; /* DNS ttl option */ long int ttl; /* CDN proxied option */ int proxied; /* * Provider specific data, per-conf-entry. E.g., the Cloudflare * plugin stores zone_id and hostname_id here. Set up by the * plugin setup callback, and is automatically freed by Inadyn. */ void *data; /* Does the provider support SSL? */ int ssl_enabled; int append_myip; /* For custom setups! */ } ddns_info_t; /* Client context */ typedef struct { char *cfgfile; ddns_cmd_t cmd; int update_period; /* time between 2 updates */ int normal_update_period_sec; int error_update_period_sec; int forced_update_period_sec; int forced_update_fake_addr; int cmd_check_period; /*time to wait for a command */ int total_iterations; int num_iterations; int initialized; int change_persona; int force_addr_update; int use_proxy; int abort; http_trans_t http_transaction; char *work_buf; /* for HTTP responses */ int work_buflen; char *request_buf; /* for HTTP requests */ size_t request_buflen; } ddns_t; extern int once; extern int force; extern int ignore_errors; extern int startup_delay; extern int allow_ipv6; extern int verify_addr; extern int exec_mode; extern char *ident; extern char *prognm; extern char *iface; extern char *use_iface; /* Command line option */ extern char *user_agent; extern char *script_cmd; extern char *script_exec; extern char *pidfile_name; extern char *generic_responses[]; extern uid_t uid; extern gid_t gid; int ddns_main_loop (ddns_t *ctx); int common_request (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); int common_response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias); #endif /* DDNS_H_ */ /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/include/error.h000066400000000000000000000056061400562756000157450ustar00rootroot00000000000000/* Error code definitions * * Copyright (C) 2003-2004 Narcis Ilisei * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef INADYN_ERROR_H_ #define INADYN_ERROR_H_ #define RC_OK 0 #define RC_ERROR 1 #define RC_INVALID_POINTER 2 #define RC_OUT_OF_MEMORY 3 #define RC_BUFFER_OVERFLOW 4 #define RC_PIDFILE_EXISTS_ALREADY 5 #define RC_TCP_SOCKET_CREATE_ERROR 10 #define RC_TCP_BAD_PARAMETER 11 #define RC_TCP_INVALID_REMOTE_ADDR 12 #define RC_TCP_CONNECT_FAILED 13 #define RC_TCP_SEND_ERROR 14 #define RC_TCP_RECV_ERROR 15 #define RC_TCP_OBJECT_NOT_INITIALIZED 16 #define RC_HTTP_OBJECT_NOT_INITIALIZED 22 #define RC_HTTPS_NO_TRUSTED_CA_STORE 31 #define RC_HTTPS_OUT_OF_MEMORY 32 #define RC_HTTPS_FAILED_CONNECT 33 #define RC_HTTPS_FAILED_GETTING_CERT 34 #define RC_HTTPS_SEND_ERROR 36 #define RC_HTTPS_RECV_ERROR 37 #define RC_HTTPS_SNI_ERROR 38 #define RC_HTTPS_INVALID_REQUEST 39 #define RC_DDNS_INVALID_CHECKIP_RSP 42 #define RC_DDNS_INVALID_OPTION 45 #define RC_DDNS_RSP_NOHOST 47 #define RC_DDNS_RSP_NOTOK 48 #define RC_DDNS_RSP_RETRY_LATER 49 #define RC_DDNS_RSP_AUTH_FAIL 50 #define RC_OS_INVALID_IP_ADDRESS 61 #define RC_OS_FORK_FAILURE 62 #define RC_OS_CHANGE_PERSONA_FAILURE 63 #define RC_OS_INVALID_UID 64 #define RC_OS_INVALID_GID 65 #define RC_OS_INSTALL_SIGHANDLER_FAILED 66 #define RC_FILE_IO_ACCESS_ERROR 73 #define RC_FILE_IO_MISSING_FILE 74 #define RC_RESTART 255 #define DO(fn) { int rc = fn; if (rc) return rc; } #define TRY(fn) { rc = fn; if (rc) break; } #define ASSERT(cond) { if (!cond) return RC_INVALID_POINTER; } const char *error_str(int rc); #endif /* INADYN_ERROR_H_ */ /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/include/http.h000066400000000000000000000050211400562756000155620ustar00rootroot00000000000000/* Interface for HTTP functions * * Copyright (C) 2003-2004 Narcis Ilisei * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef INADYN_HTTP_H_ #define INADYN_HTTP_H_ #include "config.h" #if defined(CONFIG_OPENSSL) #include #include #include #include #include #include #include #elif defined(CONFIG_GNUTLS) #include #endif #include "error.h" #include "os.h" #include "tcp.h" #define HTTP_DEFAULT_TIMEOUT 10000 /* msec */ #define HTTP_DEFAULT_PORT 80 #define HTTPS_DEFAULT_PORT 443 typedef struct { tcp_sock_t tcp; int ssl_enabled; #ifdef ENABLE_SSL #ifdef CONFIG_OPENSSL SSL *ssl; SSL_CTX *ssl_ctx; #else gnutls_session_t ssl; #endif #endif int initialized; } http_t; typedef struct { char *req; int req_len; char *rsp; int rsp_len; int max_rsp_len; char *rsp_body; int status; char status_desc[256]; } http_trans_t; int http_construct (http_t *client); int http_destruct (http_t *client, int num); int http_init (http_t *client, char *msg); int http_exit (http_t *client); int http_transaction (http_t *client, http_trans_t *trans); int http_status_valid (int status); int http_set_port (http_t *client, int porg); int http_get_port (http_t *client, int *port); int http_set_remote_name (http_t *client, const char *name); int http_get_remote_name (http_t *client, const char **name); int http_set_remote_timeout (http_t *client, int timeout); int http_get_remote_timeout (http_t *client, int *timeout); #endif /* INADYN_HTTP_H_ */ /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/include/jsmn.h000066400000000000000000000273671400562756000155730ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2010 Serge Zaitsev * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef JSMN_H #define JSMN_H #include #ifdef __cplusplus extern "C" { #endif #ifdef JSMN_STATIC #define JSMN_API static #else #define JSMN_API extern #endif /** * JSON type identifier. Basic types are: * o Object * o Array * o String * o Other primitive: number, boolean (true/false) or null */ typedef enum { JSMN_UNDEFINED = 0, JSMN_OBJECT = 1, JSMN_ARRAY = 2, JSMN_STRING = 3, JSMN_PRIMITIVE = 4 } jsmntype_t; enum jsmnerr { /* Not enough tokens were provided */ JSMN_ERROR_NOMEM = -1, /* Invalid character inside JSON string */ JSMN_ERROR_INVAL = -2, /* The string is not a full JSON packet, more bytes expected */ JSMN_ERROR_PART = -3 }; /** * JSON token description. * type type (object, array, string etc.) * start start position in JSON data string * end end position in JSON data string */ typedef struct { jsmntype_t type; int start; int end; int size; #ifdef JSMN_PARENT_LINKS int parent; #endif } jsmntok_t; /** * JSON parser. Contains an array of token blocks available. Also stores * the string being parsed now and current position in that string. */ typedef struct { unsigned int pos; /* offset in the JSON string */ unsigned int toknext; /* next token to allocate */ int toksuper; /* superior token node, e.g. parent object or array */ } jsmn_parser; /** * Create JSON parser over an array of tokens */ JSMN_API void jsmn_init(jsmn_parser *parser); /** * Run JSON parser. It parses a JSON data string into and array of tokens, each * describing * a single JSON object. */ JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, jsmntok_t *tokens, const unsigned int num_tokens); #ifndef JSMN_HEADER /** * Allocates a fresh unused token from the token pool. */ static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens, const size_t num_tokens) { jsmntok_t *tok; if (parser->toknext >= num_tokens) { return NULL; } tok = &tokens[parser->toknext++]; tok->start = tok->end = -1; tok->size = 0; #ifdef JSMN_PARENT_LINKS tok->parent = -1; #endif return tok; } /** * Fills token type and boundaries. */ static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type, const int start, const int end) { token->type = type; token->start = start; token->end = end; token->size = 0; } /** * Fills next available token with JSON primitive. */ static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, const size_t len, jsmntok_t *tokens, const size_t num_tokens) { jsmntok_t *token; int start; start = parser->pos; for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { switch (js[parser->pos]) { #ifndef JSMN_STRICT /* In strict mode primitive must be followed by "," or "}" or "]" */ case ':': #endif case '\t': case '\r': case '\n': case ' ': case ',': case ']': case '}': goto found; } if (js[parser->pos] < 32 || js[parser->pos] >= 127) { parser->pos = start; return JSMN_ERROR_INVAL; } } #ifdef JSMN_STRICT /* In strict mode primitive must be followed by a comma/object/array */ parser->pos = start; return JSMN_ERROR_PART; #endif found: if (tokens == NULL) { parser->pos--; return 0; } token = jsmn_alloc_token(parser, tokens, num_tokens); if (token == NULL) { parser->pos = start; return JSMN_ERROR_NOMEM; } jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); #ifdef JSMN_PARENT_LINKS token->parent = parser->toksuper; #endif parser->pos--; return 0; } /** * Fills next token with JSON string. */ static int jsmn_parse_string(jsmn_parser *parser, const char *js, const size_t len, jsmntok_t *tokens, const size_t num_tokens) { jsmntok_t *token; int start = parser->pos; parser->pos++; /* Skip starting quote */ for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { char c = js[parser->pos]; /* Quote: end of string */ if (c == '\"') { if (tokens == NULL) { return 0; } token = jsmn_alloc_token(parser, tokens, num_tokens); if (token == NULL) { parser->pos = start; return JSMN_ERROR_NOMEM; } jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos); #ifdef JSMN_PARENT_LINKS token->parent = parser->toksuper; #endif return 0; } /* Backslash: Quoted symbol expected */ if (c == '\\' && parser->pos + 1 < len) { int i; parser->pos++; switch (js[parser->pos]) { /* Allowed escaped symbols */ case '\"': case '/': case '\\': case 'b': case 'f': case 'r': case 'n': case 't': break; /* Allows escaped symbol \uXXXX */ case 'u': parser->pos++; for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) { /* If it isn't a hex character we have an error */ if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ parser->pos = start; return JSMN_ERROR_INVAL; } parser->pos++; } parser->pos--; break; /* Unexpected symbol */ default: parser->pos = start; return JSMN_ERROR_INVAL; } } } parser->pos = start; return JSMN_ERROR_PART; } /** * Parse JSON string and fill tokens. */ JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, jsmntok_t *tokens, const unsigned int num_tokens) { int r; int i; jsmntok_t *token; int count = parser->toknext; for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { char c; jsmntype_t type; c = js[parser->pos]; switch (c) { case '{': case '[': count++; if (tokens == NULL) { break; } token = jsmn_alloc_token(parser, tokens, num_tokens); if (token == NULL) { return JSMN_ERROR_NOMEM; } if (parser->toksuper != -1) { jsmntok_t *t = &tokens[parser->toksuper]; #ifdef JSMN_STRICT /* In strict mode an object or array can't become a key */ if (t->type == JSMN_OBJECT) { return JSMN_ERROR_INVAL; } #endif t->size++; #ifdef JSMN_PARENT_LINKS token->parent = parser->toksuper; #endif } token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); token->start = parser->pos; parser->toksuper = parser->toknext - 1; break; case '}': case ']': if (tokens == NULL) { break; } type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); #ifdef JSMN_PARENT_LINKS if (parser->toknext < 1) { return JSMN_ERROR_INVAL; } token = &tokens[parser->toknext - 1]; for (;;) { if (token->start != -1 && token->end == -1) { if (token->type != type) { return JSMN_ERROR_INVAL; } token->end = parser->pos + 1; parser->toksuper = token->parent; break; } if (token->parent == -1) { if (token->type != type || parser->toksuper == -1) { return JSMN_ERROR_INVAL; } break; } token = &tokens[token->parent]; } #else for (i = parser->toknext - 1; i >= 0; i--) { token = &tokens[i]; if (token->start != -1 && token->end == -1) { if (token->type != type) { return JSMN_ERROR_INVAL; } parser->toksuper = -1; token->end = parser->pos + 1; break; } } /* Error if unmatched closing bracket */ if (i == -1) { return JSMN_ERROR_INVAL; } for (; i >= 0; i--) { token = &tokens[i]; if (token->start != -1 && token->end == -1) { parser->toksuper = i; break; } } #endif break; case '\"': r = jsmn_parse_string(parser, js, len, tokens, num_tokens); if (r < 0) { return r; } count++; if (parser->toksuper != -1 && tokens != NULL) { tokens[parser->toksuper].size++; } break; case '\t': case '\r': case '\n': case ' ': break; case ':': parser->toksuper = parser->toknext - 1; break; case ',': if (tokens != NULL && parser->toksuper != -1 && tokens[parser->toksuper].type != JSMN_ARRAY && tokens[parser->toksuper].type != JSMN_OBJECT) { #ifdef JSMN_PARENT_LINKS parser->toksuper = tokens[parser->toksuper].parent; #else for (i = parser->toknext - 1; i >= 0; i--) { if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { if (tokens[i].start != -1 && tokens[i].end == -1) { parser->toksuper = i; break; } } } #endif } break; #ifdef JSMN_STRICT /* In strict mode primitives are: numbers and booleans */ case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 't': case 'f': case 'n': /* And they must not be keys of the object */ if (tokens != NULL && parser->toksuper != -1) { const jsmntok_t *t = &tokens[parser->toksuper]; if (t->type == JSMN_OBJECT || (t->type == JSMN_STRING && t->size != 0)) { return JSMN_ERROR_INVAL; } } #else /* In non-strict mode every unquoted value is a primitive */ default: #endif r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); if (r < 0) { return r; } count++; if (parser->toksuper != -1 && tokens != NULL) { tokens[parser->toksuper].size++; } break; #ifdef JSMN_STRICT /* Unexpected char in strict mode */ default: return JSMN_ERROR_INVAL; #endif } } if (tokens != NULL) { for (i = parser->toknext - 1; i >= 0; i--) { /* Unmatched opened object or array */ if (tokens[i].start != -1 && tokens[i].end == -1) { return JSMN_ERROR_PART; } } } return count; } /** * Creates a new parser based over a given buffer with an array of tokens * available. */ JSMN_API void jsmn_init(jsmn_parser *parser) { parser->pos = 0; parser->toknext = 0; parser->toksuper = -1; } #endif /* JSMN_HEADER */ #ifdef __cplusplus } #endif #endif /* JSMN_H */ inadyn-2.8.1/include/json.h000066400000000000000000000022331400562756000155560ustar00rootroot00000000000000/* JSON helpers * * Copyright (C) 2019-2020 Simon Pilkington * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef INADYN_JSON_H_ #define INADYN_JSON_H_ #define JSMN_HEADER #include "jsmn.h" int parse_json(const char *json, jsmntok_t *out_tokens[]); int jsoneq(const char *json, const jsmntok_t *tok, const char *s); int json_bool(const char *json, const jsmntok_t *token, int *out_value); #endif inadyn-2.8.1/include/log.h000066400000000000000000000024611400562756000153710ustar00rootroot00000000000000/* Custom error logging system * * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef INADYN_LOG_H_ #define INADYN_LOG_H_ #include #include "os.h" void log_init (char *ident, int log, int bg); void log_exit (void); int log_level (char *level); void logit (int prio, const char *fmt, ...); void vlogit (int prio, const char *fmt, va_list args); #endif /* INADYN_LOG_H_ */ /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/include/md5.h000066400000000000000000000043751400562756000153030ustar00rootroot00000000000000/** * \file md5.h * * \brief MD5 message digest algorithm (hash function) * * Copyright (C) 2006-2010, Brainspark B.V. * * This file is part of PolarSSL (http://www.polarssl.org) * Lead Maintainer: Paul Bakker * * All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef MD5_H #define MD5_H #include #include /** * \brief MD5 context structure */ typedef struct { unsigned long total[2]; /*!< number of bytes processed */ unsigned long state[4]; /*!< intermediate digest state */ unsigned char buffer[64]; /*!< data block being processed */ } md5_context; /** * \brief MD5 context setup * * \param ctx context to be initialized */ void md5_starts( md5_context *ctx ); /** * \brief MD5 process buffer * * \param ctx MD5 context * \param input buffer holding the data * \param ilen length of the input data */ void md5_update( md5_context *ctx, const unsigned char *input, size_t ilen ); /** * \brief MD5 final digest * * \param ctx MD5 context * \param output MD5 checksum result */ void md5_finish( md5_context *ctx, unsigned char output[16] ); /** * \brief Output = MD5( input buffer ) * * \param input buffer holding the data * \param ilen length of the input data * \param output MD5 checksum result */ void md5( const unsigned char *input, size_t ilen, unsigned char output[16] ); #endif /* md5.h */ inadyn-2.8.1/include/os.h000066400000000000000000000041561400562756000152340ustar00rootroot00000000000000/* * Copyright (C) 2003-2004 Narcis Ilisei * Copyright (C) 2006 Steve Horbachuk * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef INADYN_OS_H_ #define INADYN_OS_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef IN_PRIVATE #define IN_PRIVATE(addr) (((addr & IN_CLASSA_NET) == 0x0a000000) || \ ((addr & 0xfff00000) == 0xac100000) || \ ((addr & IN_CLASSB_NET) == 0xc0a80000)) #endif #ifndef IN_LINKLOCAL #define IN_LINKLOCALNETNUM 0xa9fe0000 #define IN_LINKLOCAL(addr) ((addr & IN_CLASSB_NET) == IN_LINKLOCALNETNUM) #endif #ifndef IN_LOOPBACK #define IN_LOOPBACK(addr) ((addr & IN_CLASSA_NET) == 0x7f000000) #endif #ifndef IN_ZERONET #define IN_ZERONET(addr) ((addr & IN_CLASSA_NET) == 0) #endif #include "error.h" int os_install_signal_handler (void *ctx); int os_check_perms (void); int os_shell_execute (char *cmd, char *ip, char *hostname, char *event, int error); #endif /* INADYN_OS_H_ */ /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/include/plugin.h000066400000000000000000000054041400562756000161060ustar00rootroot00000000000000/* DDNS Provider Plugin API for Inadyn * * Copyright (c) 2012-2020 Joachim Nilsson * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef INADYN_PLUGIN_H_ #define INADYN_PLUGIN_H_ #include "queue.h" /* BSD sys/queue.h API */ #define GENERIC_HTTP_REQUEST \ "GET %s HTTP/1.0\r\n" \ "Host: %s\r\n" \ "User-Agent: %s\r\n\r\n" #define PLUGIN_INIT(x) static void __attribute__ ((constructor)) x(void) #define PLUGIN_EXIT(x) static void __attribute__ ((destructor)) x(void) #define PLUGIN_ITERATOR(x, tmp) TAILQ_FOREACH_SAFE(x, &plugins, link, tmp) /* Types used for DNS system specific configuration */ /* Function to prepare DNS system specific server requests */ typedef int (*setup_fn_t) (void* this, void* info, void* alias); typedef int (*req_fn_t) (void *this, void *info, void *alias); typedef int (*rsp_fn_t) (void *this, void *info, void *alias); typedef struct ddns_system { TAILQ_ENTRY(ddns_system) link; /* BSD sys/queue.h linked list node. */ const char *name; setup_fn_t setup; req_fn_t request; rsp_fn_t response; const int nousername; /* Provider does not require username='' */ const char *checkip_name; const char *checkip_url; const int checkip_ssl; const char *server_name; const char *server_url; } ddns_system_t; /* Public plugin API */ int plugin_register (ddns_system_t *system); int plugin_unregister (ddns_system_t *system); /* Helper API */ ddns_system_t *plugin_find (const char *name, int loose); /* Looks ugly, placed here due to deps. and to make it easier for plugin devs */ #include "ddns.h" #endif /* INADYN_PLUGIN_H_ */ /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/include/queue.h000066400000000000000000000436211400562756000157370ustar00rootroot00000000000000/* $OpenBSD: queue.h,v 1.43 2015/12/28 19:38:40 millert Exp $ */ /* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ /* * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)queue.h 8.5 (Berkeley) 8/20/94 */ #ifndef _SYS_QUEUE_H_ #define _SYS_QUEUE_H_ /* * This file defines five types of data structures: singly-linked lists, * lists, simple queues, tail queues and XOR simple queues. * * * A singly-linked list is headed by a single forward pointer. The elements * are singly linked for minimum space and pointer manipulation overhead at * the expense of O(n) removal for arbitrary elements. New elements can be * added to the list after an existing element or at the head of the list. * Elements being removed from the head of the list should use the explicit * macro for this purpose for optimum efficiency. A singly-linked list may * only be traversed in the forward direction. Singly-linked lists are ideal * for applications with large datasets and few or no removals or for * implementing a LIFO queue. * * A list is headed by a single forward pointer (or an array of forward * pointers for a hash table header). The elements are doubly linked * so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before * or after an existing element or at the head of the list. A list * may only be traversed in the forward direction. * * A simple queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are singly * linked to save space, so elements can only be removed from the * head of the list. New elements can be added to the list before or after * an existing element, at the head of the list, or at the end of the * list. A simple queue may only be traversed in the forward direction. * * A tail queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or * after an existing element, at the head of the list, or at the end of * the list. A tail queue may be traversed in either direction. * * An XOR simple queue is used in the same way as a regular simple queue. * The difference is that the head structure also includes a "cookie" that * is XOR'd with the queue pointer (first, last or next) to generate the * real pointer value. * * For details on the use of these macros, see the queue(3) manual page. */ #if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) #define _Q_INVALIDATE(a) (a) = ((void *)-1) #else #define _Q_INVALIDATE(a) #endif /* * Singly-linked List definitions. */ #define SLIST_HEAD(name, type) \ struct name { \ struct type *slh_first; /* first element */ \ } #define SLIST_HEAD_INITIALIZER(head) \ { NULL } #define SLIST_ENTRY(type) \ struct { \ struct type *sle_next; /* next element */ \ } /* * Singly-linked List access methods. */ #define SLIST_FIRST(head) ((head)->slh_first) #define SLIST_END(head) NULL #define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) #define SLIST_FOREACH(var, head, field) \ for((var) = SLIST_FIRST(head); \ (var) != SLIST_END(head); \ (var) = SLIST_NEXT(var, field)) #define SLIST_FOREACH_SAFE(var, head, field, tvar) \ for ((var) = SLIST_FIRST(head); \ (var) && ((tvar) = SLIST_NEXT(var, field), 1); \ (var) = (tvar)) /* * Singly-linked List functions. */ #define SLIST_INIT(head) { \ SLIST_FIRST(head) = SLIST_END(head); \ } #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ (elm)->field.sle_next = (slistelm)->field.sle_next; \ (slistelm)->field.sle_next = (elm); \ } while (0) #define SLIST_INSERT_HEAD(head, elm, field) do { \ (elm)->field.sle_next = (head)->slh_first; \ (head)->slh_first = (elm); \ } while (0) #define SLIST_REMOVE_AFTER(elm, field) do { \ (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ } while (0) #define SLIST_REMOVE_HEAD(head, field) do { \ (head)->slh_first = (head)->slh_first->field.sle_next; \ } while (0) #define SLIST_REMOVE(head, elm, type, field) do { \ if ((head)->slh_first == (elm)) { \ SLIST_REMOVE_HEAD((head), field); \ } else { \ struct type *curelm = (head)->slh_first; \ \ while (curelm->field.sle_next != (elm)) \ curelm = curelm->field.sle_next; \ curelm->field.sle_next = \ curelm->field.sle_next->field.sle_next; \ } \ _Q_INVALIDATE((elm)->field.sle_next); \ } while (0) /* * List definitions. */ #define LIST_HEAD(name, type) \ struct name { \ struct type *lh_first; /* first element */ \ } #define LIST_HEAD_INITIALIZER(head) \ { NULL } #define LIST_ENTRY(type) \ struct { \ struct type *le_next; /* next element */ \ struct type **le_prev; /* address of previous next element */ \ } /* * List access methods. */ #define LIST_FIRST(head) ((head)->lh_first) #define LIST_END(head) NULL #define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) #define LIST_NEXT(elm, field) ((elm)->field.le_next) #define LIST_FOREACH(var, head, field) \ for((var) = LIST_FIRST(head); \ (var)!= LIST_END(head); \ (var) = LIST_NEXT(var, field)) #define LIST_FOREACH_SAFE(var, head, field, tvar) \ for ((var) = LIST_FIRST(head); \ (var) && ((tvar) = LIST_NEXT(var, field), 1); \ (var) = (tvar)) /* * List functions. */ #define LIST_INIT(head) do { \ LIST_FIRST(head) = LIST_END(head); \ } while (0) #define LIST_INSERT_AFTER(listelm, elm, field) do { \ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ (listelm)->field.le_next->field.le_prev = \ &(elm)->field.le_next; \ (listelm)->field.le_next = (elm); \ (elm)->field.le_prev = &(listelm)->field.le_next; \ } while (0) #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.le_prev = (listelm)->field.le_prev; \ (elm)->field.le_next = (listelm); \ *(listelm)->field.le_prev = (elm); \ (listelm)->field.le_prev = &(elm)->field.le_next; \ } while (0) #define LIST_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.le_next = (head)->lh_first) != NULL) \ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ (head)->lh_first = (elm); \ (elm)->field.le_prev = &(head)->lh_first; \ } while (0) #define LIST_REMOVE(elm, field) do { \ if ((elm)->field.le_next != NULL) \ (elm)->field.le_next->field.le_prev = \ (elm)->field.le_prev; \ *(elm)->field.le_prev = (elm)->field.le_next; \ _Q_INVALIDATE((elm)->field.le_prev); \ _Q_INVALIDATE((elm)->field.le_next); \ } while (0) #define LIST_REPLACE(elm, elm2, field) do { \ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ (elm2)->field.le_next->field.le_prev = \ &(elm2)->field.le_next; \ (elm2)->field.le_prev = (elm)->field.le_prev; \ *(elm2)->field.le_prev = (elm2); \ _Q_INVALIDATE((elm)->field.le_prev); \ _Q_INVALIDATE((elm)->field.le_next); \ } while (0) /* * Simple queue definitions. */ #define SIMPLEQ_HEAD(name, type) \ struct name { \ struct type *sqh_first; /* first element */ \ struct type **sqh_last; /* addr of last next element */ \ } #define SIMPLEQ_HEAD_INITIALIZER(head) \ { NULL, &(head).sqh_first } #define SIMPLEQ_ENTRY(type) \ struct { \ struct type *sqe_next; /* next element */ \ } /* * Simple queue access methods. */ #define SIMPLEQ_FIRST(head) ((head)->sqh_first) #define SIMPLEQ_END(head) NULL #define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) #define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) #define SIMPLEQ_FOREACH(var, head, field) \ for((var) = SIMPLEQ_FIRST(head); \ (var) != SIMPLEQ_END(head); \ (var) = SIMPLEQ_NEXT(var, field)) #define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \ for ((var) = SIMPLEQ_FIRST(head); \ (var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \ (var) = (tvar)) /* * Simple queue functions. */ #define SIMPLEQ_INIT(head) do { \ (head)->sqh_first = NULL; \ (head)->sqh_last = &(head)->sqh_first; \ } while (0) #define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ (head)->sqh_last = &(elm)->field.sqe_next; \ (head)->sqh_first = (elm); \ } while (0) #define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.sqe_next = NULL; \ *(head)->sqh_last = (elm); \ (head)->sqh_last = &(elm)->field.sqe_next; \ } while (0) #define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ (head)->sqh_last = &(elm)->field.sqe_next; \ (listelm)->field.sqe_next = (elm); \ } while (0) #define SIMPLEQ_REMOVE_HEAD(head, field) do { \ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ (head)->sqh_last = &(head)->sqh_first; \ } while (0) #define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \ if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \ == NULL) \ (head)->sqh_last = &(elm)->field.sqe_next; \ } while (0) #define SIMPLEQ_CONCAT(head1, head2) do { \ if (!SIMPLEQ_EMPTY((head2))) { \ *(head1)->sqh_last = (head2)->sqh_first; \ (head1)->sqh_last = (head2)->sqh_last; \ SIMPLEQ_INIT((head2)); \ } \ } while (0) /* * XOR Simple queue definitions. */ #define XSIMPLEQ_HEAD(name, type) \ struct name { \ struct type *sqx_first; /* first element */ \ struct type **sqx_last; /* addr of last next element */ \ unsigned long sqx_cookie; \ } #define XSIMPLEQ_ENTRY(type) \ struct { \ struct type *sqx_next; /* next element */ \ } /* * XOR Simple queue access methods. */ #define XSIMPLEQ_XOR(head, ptr) ((__typeof(ptr))((head)->sqx_cookie ^ \ (unsigned long)(ptr))) #define XSIMPLEQ_FIRST(head) XSIMPLEQ_XOR(head, ((head)->sqx_first)) #define XSIMPLEQ_END(head) NULL #define XSIMPLEQ_EMPTY(head) (XSIMPLEQ_FIRST(head) == XSIMPLEQ_END(head)) #define XSIMPLEQ_NEXT(head, elm, field) XSIMPLEQ_XOR(head, ((elm)->field.sqx_next)) #define XSIMPLEQ_FOREACH(var, head, field) \ for ((var) = XSIMPLEQ_FIRST(head); \ (var) != XSIMPLEQ_END(head); \ (var) = XSIMPLEQ_NEXT(head, var, field)) #define XSIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \ for ((var) = XSIMPLEQ_FIRST(head); \ (var) && ((tvar) = XSIMPLEQ_NEXT(head, var, field), 1); \ (var) = (tvar)) /* * XOR Simple queue functions. */ #define XSIMPLEQ_INIT(head) do { \ arc4random_buf(&(head)->sqx_cookie, sizeof((head)->sqx_cookie)); \ (head)->sqx_first = XSIMPLEQ_XOR(head, NULL); \ (head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \ } while (0) #define XSIMPLEQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.sqx_next = (head)->sqx_first) == \ XSIMPLEQ_XOR(head, NULL)) \ (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \ (head)->sqx_first = XSIMPLEQ_XOR(head, (elm)); \ } while (0) #define XSIMPLEQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.sqx_next = XSIMPLEQ_XOR(head, NULL); \ *(XSIMPLEQ_XOR(head, (head)->sqx_last)) = XSIMPLEQ_XOR(head, (elm)); \ (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \ } while (0) #define XSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.sqx_next = (listelm)->field.sqx_next) == \ XSIMPLEQ_XOR(head, NULL)) \ (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \ (listelm)->field.sqx_next = XSIMPLEQ_XOR(head, (elm)); \ } while (0) #define XSIMPLEQ_REMOVE_HEAD(head, field) do { \ if (((head)->sqx_first = XSIMPLEQ_XOR(head, \ (head)->sqx_first)->field.sqx_next) == XSIMPLEQ_XOR(head, NULL)) \ (head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \ } while (0) #define XSIMPLEQ_REMOVE_AFTER(head, elm, field) do { \ if (((elm)->field.sqx_next = XSIMPLEQ_XOR(head, \ (elm)->field.sqx_next)->field.sqx_next) \ == XSIMPLEQ_XOR(head, NULL)) \ (head)->sqx_last = \ XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \ } while (0) /* * Tail queue definitions. */ #define TAILQ_HEAD(name, type) \ struct name { \ struct type *tqh_first; /* first element */ \ struct type **tqh_last; /* addr of last next element */ \ } #define TAILQ_HEAD_INITIALIZER(head) \ { NULL, &(head).tqh_first } #define TAILQ_ENTRY(type) \ struct { \ struct type *tqe_next; /* next element */ \ struct type **tqe_prev; /* address of previous next element */ \ } /* * Tail queue access methods. */ #define TAILQ_FIRST(head) ((head)->tqh_first) #define TAILQ_END(head) NULL #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) #define TAILQ_LAST(head, headname) \ (*(((struct headname *)((head)->tqh_last))->tqh_last)) /* XXX */ #define TAILQ_PREV(elm, headname, field) \ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) #define TAILQ_EMPTY(head) \ (TAILQ_FIRST(head) == TAILQ_END(head)) #define TAILQ_FOREACH(var, head, field) \ for((var) = TAILQ_FIRST(head); \ (var) != TAILQ_END(head); \ (var) = TAILQ_NEXT(var, field)) #define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ for ((var) = TAILQ_FIRST(head); \ (var) != TAILQ_END(head) && \ ((tvar) = TAILQ_NEXT(var, field), 1); \ (var) = (tvar)) #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ for((var) = TAILQ_LAST(head, headname); \ (var) != TAILQ_END(head); \ (var) = TAILQ_PREV(var, headname, field)) #define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ for ((var) = TAILQ_LAST(head, headname); \ (var) != TAILQ_END(head) && \ ((tvar) = TAILQ_PREV(var, headname, field), 1); \ (var) = (tvar)) /* * Tail queue functions. */ #define TAILQ_INIT(head) do { \ (head)->tqh_first = NULL; \ (head)->tqh_last = &(head)->tqh_first; \ } while (0) #define TAILQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ (head)->tqh_first->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (head)->tqh_first = (elm); \ (elm)->field.tqe_prev = &(head)->tqh_first; \ } while (0) #define TAILQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.tqe_next = NULL; \ (elm)->field.tqe_prev = (head)->tqh_last; \ *(head)->tqh_last = (elm); \ (head)->tqh_last = &(elm)->field.tqe_next; \ } while (0) #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ (elm)->field.tqe_next->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (listelm)->field.tqe_next = (elm); \ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ } while (0) #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ (elm)->field.tqe_next = (listelm); \ *(listelm)->field.tqe_prev = (elm); \ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ } while (0) #define TAILQ_REMOVE(head, elm, field) do { \ if (((elm)->field.tqe_next) != NULL) \ (elm)->field.tqe_next->field.tqe_prev = \ (elm)->field.tqe_prev; \ else \ (head)->tqh_last = (elm)->field.tqe_prev; \ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ _Q_INVALIDATE((elm)->field.tqe_prev); \ _Q_INVALIDATE((elm)->field.tqe_next); \ } while (0) #define TAILQ_REPLACE(head, elm, elm2, field) do { \ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ (elm2)->field.tqe_next->field.tqe_prev = \ &(elm2)->field.tqe_next; \ else \ (head)->tqh_last = &(elm2)->field.tqe_next; \ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ *(elm2)->field.tqe_prev = (elm2); \ _Q_INVALIDATE((elm)->field.tqe_prev); \ _Q_INVALIDATE((elm)->field.tqe_next); \ } while (0) #define TAILQ_CONCAT(head1, head2, field) do { \ if (!TAILQ_EMPTY(head2)) { \ *(head1)->tqh_last = (head2)->tqh_first; \ (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ (head1)->tqh_last = (head2)->tqh_last; \ TAILQ_INIT((head2)); \ } \ } while (0) #endif /* !_SYS_QUEUE_H_ */ inadyn-2.8.1/include/sha1.h000066400000000000000000000043741400562756000154510ustar00rootroot00000000000000/** * \file sha1.h * * \brief SHA-1 cryptographic hash function * * Copyright (C) 2006-2010, Brainspark B.V. * * This file is part of PolarSSL (http://www.polarssl.org) * Lead Maintainer: Paul Bakker * * All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef SHA1_H #define SHA1_H #include /** * \brief SHA-1 context structure */ typedef struct { unsigned long total[2]; /*!< number of bytes processed */ unsigned long state[5]; /*!< intermediate digest state */ unsigned char buffer[64]; /*!< data block being processed */ } sha1_context; /** * \brief SHA-1 context setup * * \param ctx context to be initialized */ void sha1_starts( sha1_context *ctx ); /** * \brief SHA-1 process buffer * * \param ctx SHA-1 context * \param input buffer holding the data * \param ilen length of the input data */ void sha1_update( sha1_context *ctx, const unsigned char *input, size_t ilen ); /** * \brief SHA-1 final digest * * \param ctx SHA-1 context * \param output SHA-1 checksum result */ void sha1_finish( sha1_context *ctx, unsigned char output[20] ); /** * \brief Output = SHA-1( input buffer ) * * \param input buffer holding the data * \param ilen length of the input data * \param output SHA-1 checksum result */ void sha1( const unsigned char *input, size_t ilen, unsigned char output[20] ); #endif /* sha1.h */ inadyn-2.8.1/include/ssl.h000066400000000000000000000040011400562756000154010ustar00rootroot00000000000000/* Interface for optional HTTPS functions * * Copyright (C) 2014-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef INADYN_SSL_H_ #define INADYN_SSL_H_ #include "config.h" #include "http.h" #include "tcp.h" /* User can supply local CA PEM bundle in .conf file */ extern char *ca_trust_file; /* Cert validation is enabled by default, user can disable in .conf file */ extern int secure_ssl; extern int broken_rtc; #ifdef ENABLE_SSL int ssl_init(void); void ssl_exit(void); int ssl_open(http_t *client, char *msg); int ssl_close(http_t *client); int ssl_send(http_t *client, const char *buf, int len); int ssl_recv(http_t *client, char *buf, int buf_len, int *recv_len); #else #define ssl_init() 0 #define ssl_exit() #define ssl_open(client, msg) tcp_init(&client->tcp, msg) #define ssl_close(client) tcp_exit(&client->tcp) #define ssl_send(client, buf, len) tcp_send(&client->tcp, buf, len) #define ssl_recv(client, buf, buf_len, recv_len) tcp_recv(&client->tcp, buf, buf_len, recv_len) #endif /* ENABLE_SSL */ #endif /* INADYN_SSL_H_ */ /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/include/strdupa.h000066400000000000000000000040061400562756000162670ustar00rootroot00000000000000/* ========================================================================== * strdupa.h - Re-implementation of glibc strdupa. * -------------------------------------------------------------------------- * Copyright (c) 2009 William Ahern * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to permit * persons to whom the Software is furnished to do so, subject to the * following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * ========================================================================== */ #ifndef LITE_STRDUPA_H #define LITE_STRDUPA_H #if !defined(HAVE_STRDUPA) #if defined(strdupa) #define HAVE_STRDUPA 1 #endif #endif #if !HAVE_STRDUPA #if defined(__GNUC__) #include /* size_t */ #include /* memcpy(3) strlen(3) */ #define strdupa(src) (__extension__ ({ \ size_t len_ = strlen(src); \ char *dst_ = __builtin_alloca(len_ + 1); \ dst_[len_] = '\0'; \ (char *)memcpy(dst_, src, len_); \ })) #else /* If not GCC, e.g. Clang */ #error strdupa() may use an unsupported GNU C API, please forward any fix to maintainer, cheers! #endif /* __GNUC__ */ #endif /* !HAVE_STRDUPA */ #endif /* LITE_STRDUPA_H */ inadyn-2.8.1/include/tcp.h000066400000000000000000000046541400562756000154040ustar00rootroot00000000000000/* Interface for TCP functions * * Copyright (C) 2003-2004 Narcis Ilisei * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef INADYN_TCP_H_ #define INADYN_TCP_H_ #include "os.h" #include "error.h" #define TCP_DEFAULT_TIMEOUT 5000 /* msec */ #define TCP_SOCKET_MAX_PORT 65535 #define TCP_DEFAULT_READ_CHUNK_SIZE 100 typedef enum { NO_PROXY = 0, PROXY_SOCKS4, PROXY_SOCKS4A, PROXY_SOCKS5, PROXY_SOCKS5_HOSTNAME, PROXY_HTTP_CONNECT, /* SSL only. */ } tcp_proxy_type_t; typedef struct { int initialized; int socket; const char *remote_host; unsigned short port; int timeout; tcp_proxy_type_t proxy_type; const char *proxy_host; unsigned short proxy_port; } tcp_sock_t; int tcp_construct (tcp_sock_t *tcp); int tcp_destruct (tcp_sock_t *tcp); int tcp_init (tcp_sock_t *tcp, char *msg); int tcp_exit (tcp_sock_t *tcp); int tcp_send (tcp_sock_t *tcp, const char *buf, int len); int tcp_recv (tcp_sock_t *tcp, char *buf, int len, int *recv_len); int tcp_set_port (tcp_sock_t *tcp, int port); int tcp_get_port (tcp_sock_t *tcp, int *port); int tcp_set_remote_name (tcp_sock_t *tcp, const char *name); int tcp_get_remote_name (tcp_sock_t *tcp, const char **name); int tcp_set_remote_timeout (tcp_sock_t *tcp, int timeout); int tcp_get_remote_timeout (tcp_sock_t *tcp, int *timeout); #endif /* INADYN_TCP_H_ */ /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/indent.sh000077500000000000000000000010501400562756000146250ustar00rootroot00000000000000#!/bin/sh # Linux coding style # # With the -T we can inform indent about non-ANSI/ISO types # that we've added, so indent doesn't insert spaces in odd places. # indent --linux-style --line-length112 --dont-format-comments \ -T size_t -T sigset_t -T timeval_t -T pid_t -T pthread_t \ -T time_t -T uint32_t -T uint16_t -T uint8_t -T socklen_t \ -T ddns_t -T ddns_user_t -T ddns_creds_t -T ddns_info_t -T ddns_sysinfo_t \ -T ddns_cmd_t -T ddns_system_t -T ddns_server_name_t -T ddns_alias_t \ -T http_client_t -T http_trans_t -T tcp_sock_t \ $* inadyn-2.8.1/lib/000077500000000000000000000000001400562756000135575ustar00rootroot00000000000000inadyn-2.8.1/lib/pidfile.c000066400000000000000000000073701400562756000153460ustar00rootroot00000000000000/* Updated by troglobit for libite/finit/uftpd projects 2016/07/04 */ /* $OpenBSD: pidfile.c,v 1.11 2015/06/03 02:24:36 millert Exp $ */ /* $NetBSD: pidfile.c,v 1.4 2001/02/19 22:43:42 cgd Exp $ */ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include /* utimensat() */ #include /* utimensat() on *BSD */ #include #include #include #include #include #ifndef HAVE_UTIMENSAT int utimensat(int dirfd, const char *pathname, const struct timespec ts[2], int flags); #endif static char *pidfile_path = NULL; static pid_t pidfile_pid = 0; static void pidfile_cleanup(void); const char *__pidfile_path = RUNSTATEDIR; const char *__pidfile_name = NULL; extern char *prognm; int pidfile(const char *basename) { int save_errno; int atexit_already; pid_t pid; FILE *f; if (basename == NULL) basename = prognm; pid = getpid(); atexit_already = 0; if (pidfile_path != NULL) { if (!access(pidfile_path, R_OK) && pid == pidfile_pid) { utimensat(0, pidfile_path, NULL, 0); return (0); } free(pidfile_path); pidfile_path = NULL; __pidfile_name = NULL; atexit_already = 1; } if (basename[0] != '/') { if (asprintf(&pidfile_path, "%s/%s.pid", __pidfile_path, basename) == -1) return (-1); } else { if (asprintf(&pidfile_path, "%s", basename) == -1) return (-1); } if ((f = fopen(pidfile_path, "w")) == NULL) { save_errno = errno; free(pidfile_path); pidfile_path = NULL; errno = save_errno; return (-1); } if (fprintf(f, "%ld\n", (long)pid) <= 0 || fflush(f) != 0) { save_errno = errno; (void) fclose(f); (void) unlink(pidfile_path); free(pidfile_path); pidfile_path = NULL; errno = save_errno; return (-1); } (void) fclose(f); __pidfile_name = pidfile_path; /* * LITE extension, no need to set up another atexit() handler * if user only called us to update the mtime of the PID file */ if (atexit_already) return (0); pidfile_pid = pid; if (atexit(pidfile_cleanup) < 0) { save_errno = errno; (void) unlink(pidfile_path); free(pidfile_path); pidfile_path = NULL; pidfile_pid = 0; errno = save_errno; return (-1); } return (0); } static void pidfile_cleanup(void) { if (pidfile_path != NULL && pidfile_pid == getpid()) { (void) unlink(pidfile_path); free(pidfile_path); pidfile_path = NULL; } } inadyn-2.8.1/lib/strlcat.c000066400000000000000000000033221400562756000153770ustar00rootroot00000000000000/* $OpenBSD: strlcat.c,v 1.15 2015/03/02 21:41:08 millert Exp $ */ /* * Copyright (c) 1998, 2015 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include /* * Appends src to string dst of size dsize (unlike strncat, dsize is the * full size of dst, not space left). At most dsize-1 characters * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). * Returns strlen(src) + MIN(dsize, strlen(initial dst)). * If retval >= dsize, truncation occurred. */ size_t strlcat(char *dst, const char *src, size_t dsize) { const char *odst = dst; const char *osrc = src; size_t n = dsize; size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end. */ while (n-- != 0 && *dst != '\0') dst++; dlen = dst - odst; n = dsize - dlen; if (n-- == 0) return(dlen + strlen(src)); while (*src != '\0') { if (n != 0) { *dst++ = *src; n--; } src++; } *dst = '\0'; return(dlen + (src - osrc)); /* count does not include NUL */ } inadyn-2.8.1/lib/strlcpy.c000066400000000000000000000030771400562756000154320ustar00rootroot00000000000000/* $OpenBSD: strlcpy.c,v 1.12 2015/01/15 03:54:12 millert Exp $ */ /* * Copyright (c) 1998, 2015 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include /* * Copy string src to buffer dst of size dsize. At most dsize-1 * chars will be copied. Always NUL terminates (unless dsize == 0). * Returns strlen(src); if retval >= dsize, truncation occurred. */ size_t strlcpy(char *dst, const char *src, size_t dsize) { const char *osrc = src; size_t nleft = dsize; /* Copy as many bytes as will fit. */ if (nleft != 0) { while (--nleft != 0) { if ((*dst++ = *src++) == '\0') break; } } /* Not enough room in dst, add NUL and traverse rest of src. */ if (nleft == 0) { if (dsize != 0) *dst = '\0'; /* NUL-terminate dst */ while (*src++) ; } return(src - osrc - 1); /* count does not include NUL */ } inadyn-2.8.1/lib/strtonum.c000066400000000000000000000035641400562756000156260ustar00rootroot00000000000000/* $OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $ */ /* * Copyright (c) 2004 Ted Unangst and Todd Miller * All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #define INVALID 1 #define TOOSMALL 2 #define TOOLARGE 3 #ifndef LLONG_MAX # define LLONG_MAX 0x7fffffffffffffffLL #endif #ifndef LLONG_MIN # define LLONG_MIN (-0x7fffffffffffffffLL - 1) #endif long long strtonum(const char *numstr, long long minval, long long maxval, const char **errstrp) { long long ll = 0; int error = 0; char *ep; struct errval { const char *errstr; int err; } ev[4] = { { NULL, 0 }, { "invalid", EINVAL }, { "too small", ERANGE }, { "too large", ERANGE }, }; ev[0].err = errno; errno = 0; if (minval > maxval) { error = INVALID; } else { ll = strtoll(numstr, &ep, 10); if (numstr == ep || *ep != '\0') error = INVALID; else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) error = TOOSMALL; else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) error = TOOLARGE; } if (errstrp != NULL) *errstrp = ev[error].errstr; errno = ev[error].err; if (error) ll = 0; return (ll); } inadyn-2.8.1/lib/utimensat.c000066400000000000000000000026361400562756000157430ustar00rootroot00000000000000/* Replacement in case utimensat(2) is missing * * Copyright (C) 2017-2020 Joachim Nilsson * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "config.h" #include #ifdef HAVE_FCNTL_H #include #endif #include /* lutimes(), utimes(), utimensat() */ int utimensat(int dirfd, const char *pathname, const struct timespec ts[2], int flags) { int ret = -1; struct timeval tv[2]; if (dirfd != 0) { errno = ENOTSUP; return -1; } TIMESPEC_TO_TIMEVAL(&tv[0], &ts[0]); TIMESPEC_TO_TIMEVAL(&tv[1], &ts[1]); #ifdef AT_SYMLINK_NOFOLLOW if ((flags & AT_SYMLINK_NOFOLLOW) == AT_SYMLINK_NOFOLLOW) ret = lutimes(pathname, tv); else #endif ret = utimes(pathname, tv); return ret; } inadyn-2.8.1/man/000077500000000000000000000000001400562756000135645ustar00rootroot00000000000000inadyn-2.8.1/man/Makefile.am000066400000000000000000000000711400562756000156160ustar00rootroot00000000000000dist_man5_MANS = inadyn.conf.5 dist_man8_MANS = inadyn.8 inadyn-2.8.1/man/inadyn.8000066400000000000000000000260601400562756000151430ustar00rootroot00000000000000.\" -*- nroff -*- .\" .\" Process this file with .\" groff -man -Tascii foo.1 .\" .\" Copyright (C) 2004 Shaul Karl. .\" Copyright (C) 2010-2020 Joachim Nilsson. .\" .\" You may modify and distribute this document for any purpose, as .\" long as this copyright notice remains intact. .\" .Dd February 20, 2020 .Dt INADYN 8 SMM .Os .Sh NAME .Nm inadyn .Nd Internet Automated Dynamic DNS Client .Sh SYNOPSIS .Nm inadyn .Op Fl 1, -once .Op Fl -force .Op Fl -cache-dir Ar PATH .Op Fl c, -cmd Ar /path/to/cmd .Op Fl C, -continue-on-error .Op Fl e, -exec Ar /path/to/cmd .Op Fl -exec-mode Ar MODE .Op Fl f, -config Ar FILE .Op Fl h, -help .Op Fl i, -iface Ar IFNAME .Op Fl I, -ident Ar NAME .Op Fl l, -loglevel Ar LEVEL .Op Fl n, -foreground .Op Fl -no-pidfile .Op Fl P, -pidfile Ar FILE .Op Fl p, -drop-privs Ar USER Ns Op : Ns Ar GROUP .Op Fl s, -syslog .Op Fl t, -startup-delay Ar SEC .Op Fl v, -version .Sh DESCRIPTION .Nm , or In-a-Dyn, periodically checks your actual Internet accessible IP for changes. When it changes .Nm updates your name server record(s) automatically. .Pp Common DDNS service providers supported by .Nm are listed below. Some of these services are free of charge for non-commercial use, others take a small fee, but also provide more domain names to choose from. .Pp .Nm defaults to HTTPS for all providers, some may however not support this so try disabling SSL for your provider in case of problems. Providers known to support SSL updates are listed below with .Sy https : .Pp .Bl -bullet -compact .It .Aq https://freedns.afraid.org .It .Aq https://nsupdate.info .It .Aq https://duckdns.org .It .Aq https://freemyip.com .It .Aq https://www.loopia.com .It .Aq http://www.dyndns.org , .Aq http://dyn.com .It .Aq http://www.noip.com .It .Aq http://www.easydns.com .It .Aq http://dns.he.net .It .Aq http://www.tunnelbroker.net .It .Aq https://www.dnsomatic.com .It .Aq http://www.sitelutions.com .It .Aq http://www.dnsexit.com , parent of .Aq https://zoneedit.com .It .Aq http://www.changeip.com .It .Aq http://www.dhis.org .It .Aq https://www.namecheap.com .It .Aq https://domains.google .It .Aq https://www.ovh.com .It .Aq http://giradns.com .It .Aq https://www.duiadns.net .It .Aq https://ddnss.de .It .Aq http://dynv6.com .It .Aq http://ipv4.dynv6.com .It .Aq https://spdyn.de .It .Aq https://www.cloudxns.net .It .Aq https://www.pubyun.com , formerly .Aq http://www.3322.org .It .Aq https://www.dnspod.cn .It .Aq https://www.dynu.com .It .Aq https://www.selfhost.de .It .Aq https://connect.yandex.ru .It .Aq https://www.cloudflare.com .El .Pp DDNS providers not listed here can often be configured using the generic/custom DDNS provider plugin. See .Xr inadyn.conf 5 for examples. .Sh OPTIONS Earlier versions of .Nm supported more command line options, from v2.0 .Nm has been greatly simplified. See .Xr inadyn.conf 5 for details of the .Pa /etc/inadyn.conf configuration file format. .Pp .Bl -tag -width Ds .It Fl 1, -once Run only once and quit, updates only if too old or unknown. Use .Fl -force to for an update before exiting. .It Fl -force Force one update. Only works with .Fl 1, -once flag, ignored for all other use-cases. .It Fl -cache-dir Ar PATH Set directory for persistent cache files, defaults to .Pa /var/cache/inadyn .Pp The cache files are used to keep track of which addresses have been successfully sent to their respective DDNS provider and when. The latter 'when' is important to prevent .Nm from banning you for excessive updates. .Pp When restarting .Nm or rebooting your server, or embedded device, .Nm reads the cache files to seed its internal data structures with the last sent IP address and when the update was performed. It is therefore very important to both have a cache file and for it to have the correct time stamp. The absence of a cache file will currently cause a forced update. .Pp On an embedded device with no RTC, or no battery backed RTC, it is strongly recommended to pair this setting with the .Fl -startup-delay Ar SEC command line option. .It Fl c, -cmd Ar /path/to/cmd Op optional args Full path to command, or script, to run to check for IP address change. This is the same as the configuration file option .Ar checkip-command but will apply to .Sy all providers. This command line option is only provided for convenience, it is recommended to instead use the configuration file. For more details, see the .Xr inadyn.conf 5 man page. You will need to quote the complete command if any arguments, or pipe, is given. .It Fl -continue-on-error Ignore errors from DDNS provider and try again later. This command line option tells .Nm to not exit on errors from a DDNS provider and instead try again later. Please do not use this, it usually indicates that we are sending a malformed request, e.g. wrong username, password or DNS alias for the given account. Continuing could possibly lock you out of your account! .It Fl e, -exec=/path/to/cmd Op optional args Full path to command, or script, to run. The following environment variables are set: INADYN_IP, INADYN_HOSTNAME. The first environment variable contains the new IP address, the second the host name alias. The .Nm cmd is called for each listed host name. If .Nm is started with the .Fl i Ar IFNAME command line option, the INADYN_IFACE environment variable is also set. You will need to quote the complete command if any arguments, or pipe, is given. .It Fl -exec-mode Ar MODE Use .Ar MODE to set the exec script run mode: compat, event: - compat: run exec handler on successful DDNS update only, default - event: run exec handler on any update status The following environment variables are set: INADYN_EVENT, INADYN_ERROR, INADYN_ERROR_MESSAGE. INADYN_EVENT contains the event, one of: nochg, update, error. The event nochg indicates that no update had to be sent, the event update indicates that an update was sent successully, the event error indicates that the update was sent and an error occurred. INADYN_ERROR contains the error code, INADYN_ERROR_MESSAGE contains the error message for the error code. .It Fl f, -config Ar FILE Use .Ar FILE for configuration. By default .Pa /etc/inadyn.conf , is used. See .Xr inadyn.conf 5 for examples. .It Fl h, -help Show summary of command line options and exit .It Fl i, -iface Ar IFNAME Check IP of IFNAME instead of querying an external server. With this command line option the external IP check is disabled and .Nm will report the IP address of .Ar IFNAME to all DDNS providers listed in the configuration file. This can be useful to register LAN IP addresses, or, when connected directly to a public IP address, to speed up the IP check if the DDNS provider's check-ip servers are slow to respond. .Pp This option can also be given as a configuration option in .Xr inadyn.conf 5 , both serve a purpose, use whichever one works for you. .It Fl I, Fl -ident Ar NAME Specify program identity (name) to be used for PID file and syslog messages. Useful with multiple instances of .Nm , or to simply replace the .Nm name with something more generic, e.g. "DDNS", without renaming the binary. Note, this option only changes the base name of the PID file, not the location, which is system specific. Usually .Pa /var/run/inadyn.pid or .Pa /run/inadyn.pid . .It Fl l, -loglevel Ar LEVEL Set log level: none, err, info, .Ar notice , debug. The default is .Ar notice , but you might want to set this to .Fl l Ar warning . .It Fl n, -foreground Run in foreground, default is to daemonize and continue in the background. This option is usually required when running under process supervisors like systemd and Finit, but is also useful when running from the terminal, when debugging a config or at initial set up. Remember to also give the .Fl s option if you still want to redirect log messages to the syslog. .It Fl p, -drop-privs Ar USER Ns Op : Ns Ar GROUP Drop root privileges after initial setup to the given user and group. .It Fl -no-pidfile When running as a daemon, even when running in the foreground with .Fl n , .Nm creates a PID file so users can easily find the PID of the process to send signals to. See .Sx SIGNALS for more information on this. This option tells .Nm to .Sy not create a PID file. Some users prefer this when running under systemd. .It Fl P, -pidfile Ar FILE Set PID file name and location, defaults to .Pa /run/inadyn.pid , derived from .Fl -ident Ar NAME , which is strongly recommended to change over this option. However, some users want to keep application runtime files in separate directories, usually in combination with .Fl -drop-privs , for such cases this is the option to use. .It Fl s, -syslog Use .Xr syslog 3 for log messages, warnings and error conditions. This is the default when running in the background. When running in the foreground, see .Fl n , log messages are printed to stdout. .It Fl t, -startup-delay Ar SEC Initial startup delay. Default is 0 seconds. Any signal can be used to abort the startup delay early, but SIGUSR2 is the recommended to use. See .Sx SIGNALS below for full details of how .Nm responds to signals. .Pp Intended to allow time for embedded devices without a battery backed real time clock to set their clock via NTP at bootup. This is so that the time since the last update can be calculated correctly from the .Nm cache file and the .Cm forced-update Ar SEC setting honored across reboots, avoiding unnecessary IP address updates. .It Fl v, -version Show program version and exit. .El .Sh OUTPUT .Nm prints a message when the IP is updated. If no update is needed then by default it prints a single .Dq .\& character, unless .Fl -loglevel is set to .Ar none . Therefore, unless .Fl -loglevel is set to .Ar none , the log will contain lots of dots. When the connection goes down .Nm may print some harmless error messages which should be followed by .Dq OK messages after the Internet connection is restored. .Sh SIGNALS .Nm responds to the following signals: .Pp .Bl -tag -width TERM -compact .It HUP Reload the .Nm .conf file, standard UNIX behavior .It TERM Tell .Nm to exit gracefully .It INT Same as TERM .It USR1 Force update now, even if the IP address has not changed .It USR2 Check IP address change now. Useful when a new DHCP/PPPoE lease or new gateway is received. Please note that .Nm does not track such events by itself. You need an external monitor for that .El .Pp For convenience in sending signals, .Nm writes its process ID to .Pa /var/run/inadyn.pid , unless the .Fl -ident Ar NAME option is used. .Sh FILES .Bl -tag -width /var/cache/inadyn/freedns.afraid.org.cache -compact .It Pa /etc/inadyn.conf .It Pa /run/inadyn.pid .It Pa /var/cache/inadyn/dyndns.org.cache .It Pa /var/cache/inadyn/freedns.afraid.org.cache .It Pa ... one .cache file per DDNS provider .El .Sh SEE ALSO .Xr inadyn.conf 5 .Pp The .Nm home page is at GitHub: .Aq https://github.com/troglobit/inadyn .Sh AUTHORS .Nm was originally written by Narcis Ilisei .Aq mailto:inarcis2002@hotpop.com and Steve Horbachuk. Current patch monkey is Joachim Nilsson .Aq mailto:troglobit@gmail.com with a lot of help from Andrey Tikhomirov and Mike Fleetwood. .Pp This manual page was originally written for the .Em Debian GNU/Linux project by Shaul Karl .Aq mailto:shaul@debian.org , and is currently maintained by Joachim Nilsson. inadyn-2.8.1/man/inadyn.conf.5000066400000000000000000000406731400562756000160720ustar00rootroot00000000000000.\" -*- nroff -*- .\" .\" Process this file with .\" groff -man -Tascii foo.1 .\" .\" Copyright 2005, by Shaul Karl. .\" Copyright 2010-2020, by Joachim Nilsson. .\" .\" You may modify and distribute this document for any purpose, as .\" long as this copyright notice remains intact. .\" .Dd February 20, 2020 .Dt INADYN 5 SMM .Os .Sh NAME .Nm inadyn.conf .Nd inadyn DDNS client configuration file .Sh SYNOPSIS .Nm /etc/inadyn.conf .Sh DESCRIPTION .Nm inadyn is configured using a simple configuration file. The .Dq #\& character marks start of a comment to end of line. The \\ character can be used as an escape character. .Pp .Bl -tag -width TERM .It Cm verify-address = By default .Nm inadyn verifies both IPv4 and IPv6 addresses, making sure the address is a valid Internet address. Invalid addresses are, e.g., link local, loopback, multicast and known experimental addresses. For more information, see RFC3330. .Pp IP address validation can be disabled by setting this option to .Cm false . .It Cm fake-address = When using SIGUSR1, to do a forced update, this option can be used to fake an address update with a .Dq random address in the 203.0.113.0/24 range, example address range from RFC5737, before updating with the actual IP address. This is completely outside spec., but can be useful for people who very rarely, if ever, get an IP address change. Because some DDNS service providers will not register even a forced update if the IP is the same. As a result the user could be deregistered as an inactive user. .It Cm allow-ipv6 = .Nm Inadyn can get an IPv6 address from an interface, or with an external checkip script. This option controls if IPv6 addresses should be allowed or discarded. By default this option is .Ar false , i.e. IPv6 addresses are discarded. .It Cm iface = IFNAME Use network interface .Nm IFNAME as source of IP address changes instead of querying an external server. With this option is enabled, the external IP check is disabled and .Nm inadyn will send DDNS updates using the IP address of the .Nm IFNAME network interface to .Em all DDNS providers listed in the configuration file. This can be useful to register LAN IP addresses, or, when connected directly to a public IP address, to speed up the IP check if the DDNS provider's check-ip servers are slow to respond. .Pp This option can also be given as a command line option to .Xr inadyn 8 , both serve a purpose, use whichever one works for you. .It Cm iterations = Set the number of DNS updates. The default is .Ar 0 , which means infinity. .It Cm period = SEC How often the IP is checked, in seconds. Default: apxrox. 1 minute. Max: 10 days. .It Cm forced-update = SEC How often the IP should be updated even if it is not changed. The time should be given in seconds. Default is equal to 30 days. .It Cm secure-ssl = < true | false > If the HTTPS certificate validation fails for a provider .Nm inadyn aborts the DDNS update before sending any credentials. When this setting is disabled, i.e. .Ar false , then .Nm inadyn will only issue a warning. By default this setting is enabled, because security matters. .It Cm broken-rtc = < true | false > HTTPS certificates are only valid within specified time windows, so on systems without hardware real-time clock and default bootup time far in the past, false-positive validation fail is expected. When this setting is enabled, i.e. .Ar true , then .Nm inadyn will only issue a warning that the certificate is not valid yet. By default this setting is disabled, because security matters. .It Cm ca-trust-file = FILE By default .Nm inadyn uses the built-in path to the system's trusted CA certificates, both GnuTLS and Open/LibreSSL support this. As a fall-back, in case the API's to load CA certificates from the built-in path fails, .Nm inadyn also supports common default paths to Debian and RedHat CA bundles. .Pp This setting overrides the built-in paths and fallback locations and provides a way to specify the path to a trusted set of CA certificates, in PEM format, bundled into one file. .It Cm user-agent = STRING Specify the User-Agent string to send to the DDNS provider on checkip and update requests. Some providers require this field to be set to a specific string, some may be OK with "Mozilla/4.0". The default is to send "inadyn/VERSION SUPPORTURL", where VERSION is the current .Nm inadyn version, and SUPPORTURL is the upstream support URL. .Pp This can also be set on a per-provider basis, see below custom and provider section description. .It Cm custom some@identifier {} The .Cm custom{} and .Cm provider{} sections are very similar, except that the custom section allows customizing the DDNS update server details. For more details, see the description for .Cm provider{} , below. .It Cm provider email@ddns-service.tld[:ID] {} The .Cm custom{} and .Cm provider{} sections are very similar, except that the custom section allows customizing the DDNS update server details. See below list for supported DDNS providers and their .Cm email@ddns-service.tld identifiers. .Pp To support multiple users of the same DDNS provider, append .Pa [:ID] to the provider name. The .Pa ID can be any free form string or number as long as the combination is unique. .Pp Common settings in custom{} and provider{} sections are: .Pp .Bl -tag -width TERM .It Cm ssl = Use HTTPS, both when checking for IP changes and updating the DNS record. Default is to use HTTPS (true). .It Cm username = USERNAME. The username, if applicable. This might be referred to as hash by some providers. .It Cm password = PASSWORD The password, if applicable. .It Cm checkip-server = This setting allows you to override the default checkip server with either the string .Cm default , to use In-a-dyn's built-in default, .Cm "api.ipify.org", or the complete name of the server to use for periodic IP address changes. The optional .Pa port argument defaults to .Ar 80 . .Pp This is an optional setting. For .Cm provider{} sections it defaults to a pre-defined .Cm checkip-server and .Cm checkip-path for the given DDNS provider. For custom DDNS setups it defaults to .Cm "api.ipify.org" , which is a really great and free service that even support HTTPS, see .Cm checkip-ssl setting, below. When set in a .Cm provider{} section it overrides the provider's default .Cm checkip-server . .It Cm checkip-path = "/some/checkip/url" Optional server path for check IP server, defaults to "/". When the .Cm checkip-server is set to .Cm default , this setting is ignored. .It Cm checkip-ssl = This setting usually follows the .Cm ssl setting, but can be used to disable HTTPS for the IP address check. This might be needed for some providers that only support HTTPS for the DNS record update. .Pp However, when a custom .Cm checkip-server is defined for a provider, this setting does .Em not follow the .Cm ssl setting. Default is to use HTTPS (true). .It Cm checkip-command = "/path/to/shell/command [optional args]" Shell command, or script, for IP address update checking. The command must output a text with the IP address to its standard output. The following environment variables are set: .Bl -tag -width TERM .It INADYN_PROVIDER contains the DDNS provider's full name in form .Cm email@ddns-service.tld .It INADYN_USER contains user's name .El .Pp .Pa Example: .Bd -unfilled -offset indent checkip-command = "/sbin/ifconfig eth0 | grep 'inet addr'" .Ed .Pp .Nm Inadyn will use the first occurrence in the command's output that looks like an address. Both IPv4 and IPv6 addresses are supported. .It Cm hostname = HOSTNAME .It Cm hostname = { "HOSTNAME1.name.tld", "HOSTNAME2.name.tld" } Your hostname alias. To list multiple names, use the second form. .It Cm user-agent = STRING Same as the global setting, but only for this provider. If omitted it defaults to the global setting, which if unset uses the default .Nm inadyn user agent string. For more information, see above. .It Cm wildcard = Enable domain name wildcarding of your domain name, for DDNS providers that support this, e.g. easydns.com and loopia.com. This means that anything typed before your hostname, e.g. www. or ftp., is also updated when your IP changes. Default: disabled. For .Nm inadyn < 1.96.3 wildcarding was enabled by default. .It Cm ttl = SEC Time to live of your domain name. Only works with supported DDNS providers, e.g. cloudflare.com. .It Cm proxied = Proxy DNS origin via provider's CDN network. Only works with supported DDNS providers, e.g. cloudflare.com. Default: false .El .It Cm provider [email@]ddns-service[.tld] {} Either a unique substring matching the provider, or or one of the exact matches to the following unique provider names: .Pp .Bl -tag -width TERM -compact .It Cm default@freedns.afraid.org .Aq https://freedns.afraid.org .It Cm ipv4@nsupdate.info .Aq https://nsupdate.info .It Cm default@duckdns.org .Aq https://duckdns.org .It Cm default@freemyip.com .Aq https://freemyip.com .It Cm default@loopia.com .Aq https://www.loopia.com .It Cm default@dyndns.org Connect to .Aq https://www.dyndns.org , i.e., .Aq https://dyn.com .It Cm default@noip.com .Aq https://www.noip.com .It Cm default@no-ip.com Handled by .Cm default@noip.com plugin. .It Cm default@easydns.com .Aq https://www.easydns.com .It Cm default@dnsomatic.com .Aq https://www.dnsomatic.com .It Cm dyndns@he.net .Aq https://dns.he.net .It Cm default@tunnelbroker.net IPv6 .Aq https://www.tunnelbroker.net by Hurricane Electric. .It Cm default@sitelutions.com .Aq https://www.sitelutions.com .It Cm default@dnsexit.com .Aq https://www.dnsexit.com .It Cm default@zoneedit.com .Aq https://zoneedit.com .It Cm default@changeip.com .Aq https://www.changeip.com .It Cm default@dhis.org .Aq https://www.dhis.org .It Cm default@domains.google.com .Aq https://domains.google .It Cm default@ovh.com .Aq https://www.ovh.com .It Cm default@gira.de .Aq https://giradns.com .It Cm default@duiadns.net .Aq https://www.duiadns.net .It Cm default@ddnss.de .Aq https://ddnss.de .It Cm default@dynv6.com .Aq https://dynv6.com .It Cm default@ipv4.dynv6.com .Aq https://ipv4.dynv6.com .It Cm default@spdyn.de .Aq https://spdyn.de .It Cm default@strato.com .Aq https://www.strato.com .It Cm default@cloudxns.net .Aq https://www.cloudxns.net .It Cm dyndns@3322.org .Aq https://www.3322.org .It Cm default@dnspod.cn .Aq https://www.dnspod.cn .It Cm default@dynu.com .Aq https://www.dynu.com .It Cm default@selfhost.de .Aq https://www.selfhost.de .It Cm default@pdd.yandex.ru .Aq https://connect.yandex.ru .It Cm default@cloudflare.com .Aq https://www.cloudflare.com .El .It Cm custom some@identifier {} Specific to the custom provider section are the following settings: .Pp .Bl -tag -width TERM .It Cm ddns-server = update.example.com DDNS server name, not the full URL. .It Cm ddns-path = "/update?domain=" DDNS server path. By default the hostname is appended to the path, unless .Cm append-myip=true is set. Alternatively, .Xr printf 3 like format specifiers may be used for a fully customizable HTTP GET update request. The following format specifiers are currently supported: .Pp .Bl -tag -width TERM -compact .It Cm %u username .It Cm %p password, if HTTP basic auth is not used .It Cm %h hostname .It Cm %i IP address .El .Pp With the following example: .Bd -unfilled -offset indent username = myuser password = mypass ddns-path = "/update?user=%u&password=%p&domain=%h&myip=%i" hostname = YOURDOMAIN.TLD .Ed .Pp the resulting update URL would be expanded to .Bd -unfilled -offset indent /update?user=myuser&password=mypass&domain=YOURDOMAIN.TLD&myip=1.2.3.4 .Ed .Pp However, the password is usually never sent in clear text in the HTTP GET URL. Most DDNS providers instead rely on HTTP basic auth., which .Nm inadyn always relays to the server in the HTTP header of update requests. .Nm v2.1 and later defaults to HTTPS to protect your credentials, but some providers still do not support HTTPS. .It Cm append-myip = true Append your current IP to the the DDNS server update path. By default this setting is false and the hostname is appended. Unless the .Cm ddns-path is given with format specifiers, in which case this setting is unused. .El .El .Sh EXAMPLES Worth noting below is how two different user accounts can use the same DDNS provider, No-IP.com, by using the concept of instances ':N'. .Bd -unfilled -offset indent period = 300 # Dyn.com provider dyndns.org { username = account1 password = secret1 hostname = { "my.example.com", "other.example.org" } } # FreeDNS. Remember the username must be in lower case # and password (max 16 chars) is case sensitive. provider freedns { username = lower-case-username password = case-sensitive-pwd hostname = some.example.com } # No-IP.com #1 provider no-ip.com:1 { checkip-server = "dynamic.zoneedit.com" checkip-path = "/checkip.html" checkip-ssl = false username = account21 password = secret21 hostname = example.no-ip.com } # No-IP.com #2 provider no-ip.com:2 { username = account22 password = secret22 hostname = another.no-ip.com } # Google Domains - notice use of '@' to update root entry provider domains.google.com { hostname = @.mydomain.com username = your_username password = your_password } # Loopia provider loopia.com { wildcard = true username = account3 password = secret3 hostname = example.com } # ddnss.de provider ddnss.de { username = your_username password = your_password hostname = your_host.ddnss.de } # spdyn.de provider spdyn.de { username = your_username password = your_password hostname = your_host.spdyn.de } # www.strato.com provider strato.com { username = your_username password = your_password hostname = example.com } # dynv6.com provider dynv6.com { username = your_token password = not_used hostname = your_host.dynv6.net } # IPv6 account at https://tunnelbroker.net provider tunnelbroker.net { username = xyzzy password = update-key-in-advanced-tab hostname = tunnel-id } # www.freemyip.com provider freemyip.com { password = your_token hostname = your_hostname.freemyip.com } # www.cloudxns.net provider cloudxns.net { username = your_api_key password = your_secret_key hostname = yourhost.example.com } # www.dnspod.cn provider dnspod.cn { username = your_api_id password = your_api_token hostname = yourhost.example.com } # www.cloudflare.com provider cloudflare.com { username = zone.name password = api_token # Create a unique custom api token with the following permissions: Zone.Zone - Read, Zone.DNS - Edit. hostname = hostname.zone.name ttl = 1 # optional, value of 1 is 'automatic'. proxied = false # optional. } # Generic example, check all details for your provider! custom example { username = myuser password = mypass checkip-server = checkip.example.com checkip-path = / checkip-ssl = false ddns-server = update.example.com ddns-path = "/update?hostname=" hostname = myhostname.example.net } .Ed .Pp As of Inadyn 1.99.14 the generic plugin can also be used with providers that require the client's IP in the update request, which for example .Aq https://dyn.com requires: .Bd -unfilled -offset indent # This emulates dyndns.org custom dyn.com { username = DYNUSERNAME password = DYNPASSWORD ddns-server = members.dyndns.org ddns-path = "/nic/update?hostname=YOURHOST.dyndns.org&myip=" append-myip = true hostname = YOURHOST } .Ed .Pp Notice the use of .Nm append-myip which differs from above previous examples. Without this option set the default (backwards compatible) behavior is to append the hostname. .Pp An alternative, and perhaps more intuitive approach introduced in Inadyn v2.0, is to use the .Xr printf 3 like format specifiers mentioned previously. The same example look like this: .Bd -unfilled -offset indent # This emulates dyndns.org custom dyn.com { ssl = false username = DYNUSERNAME password = DYNPASSWORD ddns-server = members.dyndns.org ddns-path = "/nic/update?hostname=%h.dyndns.org&myip=%i" hostname = YOURHOST } .Ed .Sh "SEE ALSO" .Xr inadyn 8 .Pp The .Nm inadyn home page is .Aq https://github.com/troglobit/inadyn .Sh AUTHORS This manual page was initially written for the .Em Debian GNU/Linux system by .An -nosplit .An Shaul Karl Aq mailto:shaul@debian.org . Currently maintained by .An -nosplit .An Joachim Nilsson Aq mailto:troglobit@gmail.com . inadyn-2.8.1/plugins/000077500000000000000000000000001400562756000144725ustar00rootroot00000000000000inadyn-2.8.1/plugins/Makefile.am000066400000000000000000000004321400562756000165250ustar00rootroot00000000000000inadyn_SOURCES += common.c changeip.c cloudflare.c \ cloudxns.c ddnss.c dhis.c \ dnsexit.c dnspod.c duckdns.c \ duiadns.c dyndns.c dynv6.c \ easydns.c freedns.c freemyip.c \ generic.c giradns.c \ sitelutions.c tunnelbroker.c \ yandex.c zoneedit.c inadyn-2.8.1/plugins/changeip.c000066400000000000000000000061131400562756000164150ustar00rootroot00000000000000/* Plugin for ChangeIP and OVH * * Copyright (C) 2003-2004 Narcis Ilisei * Copyright (C) 2006 Steve Horbachuk * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "plugin.h" #define CHANGEIP_UPDATE_IP_HTTP_REQUEST \ "GET %s?" \ "system=dyndns&" \ "hostname=%s&" \ "myip=%s " \ "HTTP/1.0\r\n" \ "Host: %s\r\n" \ "Authorization: Basic %s\r\n" \ "User-Agent: %s\r\n\r\n" static int request (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int response (http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias); static ddns_system_t plugin = { .name = "default@changeip.com", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = "ip.changeip.com", .checkip_url = "/", .server_name = "nic.changeip.com", .server_url = "/nic/update" }; static ddns_system_t ovh = { .name = "default@ovh.com", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = DYNDNS_MY_IP_SERVER, .checkip_url = DYNDNS_MY_CHECKIP_URL, .checkip_ssl = DYNDNS_MY_IP_SSL, .server_name = "www.ovh.com", .server_url = "/nic/update" }; static ddns_system_t strato = { .name = "default@strato.com", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = DYNDNS_MY_IP_SERVER, .checkip_url = DYNDNS_MY_CHECKIP_URL, .checkip_ssl = DYNDNS_MY_IP_SSL, .server_name = "dyndns.strato.com", .server_url = "/nic/update" }; static int request(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { return snprintf(ctx->request_buf, ctx->request_buflen, CHANGEIP_UPDATE_IP_HTTP_REQUEST, info->server_url, alias->name, alias->address, info->server_name.name, info->creds.encoded_password, info->user_agent); } static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias) { return common_response(trans, info, alias); } PLUGIN_INIT(plugin_init) { plugin_register(&plugin); plugin_register(&ovh); plugin_register(&strato); } PLUGIN_EXIT(plugin_exit) { plugin_unregister(&plugin); plugin_unregister(&ovh); plugin_unregister(&strato); } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/plugins/cloudflare.c000066400000000000000000000253371400562756000167700ustar00rootroot00000000000000/* Plugin for Cloudflare * * Copyright (C) 2019-2020 Simon Pilkington * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "plugin.h" #include "json.h" #define CHECK(fn) { rc = (fn); if (rc) goto cleanup; } #define API_HOST "api.cloudflare.com" #define API_URL "/client/v4" static const char *CLOUDFLARE_ZONE_ID_REQUEST = "GET " API_URL "/zones?name=%s HTTP/1.0\r\n" \ "Host: " API_HOST "\r\n" \ "User-Agent: %s\r\n" \ "Accept: */*\r\n" \ "Authorization: Bearer %s\r\n" \ "Content-Type: application/json\r\n\r\n"; static const char *CLOUDFLARE_HOSTNAME_ID_REQUEST = "GET " API_URL "/zones/%s/dns_records?type=%s&name=%s HTTP/1.0\r\n" \ "Host: " API_HOST "\r\n" \ "User-Agent: %s\r\n" \ "Accept: */*\r\n" \ "Authorization: Bearer %s\r\n" \ "Content-Type: application/json\r\n\r\n"; static const char *CLOUDFLARE_HOSTNAME_CREATE_REQUEST = "POST " API_URL "/zones/%s/dns_records HTTP/1.0\r\n" \ "Host: " API_HOST "\r\n" \ "User-Agent: %s\r\n" \ "Accept: */*\r\n" \ "Authorization: Bearer %s\r\n" \ "Content-Type: application/json\r\n" \ "Content-Length: %zd\r\n\r\n" \ "%s"; static const char *CLOUDFLARE_HOSTNAME_UPDATE_REQUEST = "PUT " API_URL "/zones/%s/dns_records/%s HTTP/1.0\r\n" \ "Host: " API_HOST "\r\n" \ "User-Agent: %s\r\n" \ "Accept: */*\r\n" \ "Authorization: Bearer %s\r\n" \ "Content-Type: application/json\r\n" \ "Content-Length: %zd\r\n\r\n" \ "%s"; static const char *CLOUDFLARE_UPDATE_JSON_FORMAT = "{\"type\":\"%s\",\"name\":\"%s\",\"content\":\"%s\",\"ttl\":%li,\"proxied\":%s}"; static const char *IPV4_RECORD_TYPE = "A"; static const char *IPV6_RECORD_TYPE = "AAAA"; static const char *KEY_SUCCESS = "success"; static int setup (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *hostname); static int request (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *hostname); static int response (http_trans_t *trans, ddns_info_t *info, ddns_alias_t *hostname); static ddns_system_t plugin = { .name = "default@cloudflare.com", .setup = (setup_fn_t)setup, .request = (req_fn_t)request, .response = (rsp_fn_t)response, /* * 1.1.1.1 is chosen here due to "allow-ipv6" is default to false * www.cloudflare.com would also work but is dual stack and may return ipv6 address * use 1.1.1.1 to would force it return ipv4 by default * see examples/cloudflare-*.conf */ .checkip_name = "1.1.1.1", .checkip_url = "/cdn-cgi/trace", .checkip_ssl = DDNS_CHECKIP_SSL_SUPPORTED, .server_name = API_HOST, .server_url = API_URL }; /* * filled by the setup() callback and handed to ddns_info_t * for use later in the request() callback . */ #define MAX_ID (32 + 1) struct cfdata { char zone_id[MAX_ID]; char hostname_id[MAX_ID]; }; static int check_response_code(int status) { switch (status) { case 200: case 304: return RC_OK; case 400: logit(LOG_ERR, "HTTP 400: Cloudflare says our request was invalid. Possibly a malformed API token."); return RC_DDNS_RSP_NOTOK; case 403: logit(LOG_ERR, "HTTP 403: Provided API token does not have the required permissions."); return RC_DDNS_RSP_AUTH_FAIL; case 429: logit(LOG_WARNING, "HTTP 429: We got rate limited."); return RC_DDNS_RSP_RETRY_LATER; case 405: logit(LOG_ERR, "HTTP 405: Bad HTTP method; has the interface changed?"); return RC_DDNS_RSP_NOTOK; case 415: logit(LOG_ERR, "HTTP 415: Cloudflare didn't like our JSON; has the inferface changed?"); return RC_DDNS_RSP_NOTOK; default: logit(LOG_ERR, "Received status %i, don't know what that means.", status); return RC_DDNS_RSP_NOTOK; } } static int check_success(const char *json, const jsmntok_t tokens[], const int num_tokens) { for (int i = 1; i < num_tokens; i++) { int set; if (jsoneq(json, tokens + i, KEY_SUCCESS) != 0) continue; if (i < num_tokens - 1 && json_bool(json, tokens + i + 1, &set) == 0) return set ? 0 : -1; return -1; } return -1; } static int check_success_only(const char *json) { jsmntok_t *tokens; int num_tokens; int result; num_tokens = parse_json(json, &tokens); if (num_tokens == -1) return -1; result = check_success(json, tokens, num_tokens); free(tokens); return result; } static int get_result_value(const char *json, const char *key, jsmntok_t *out_result) { jsmntok_t *tokens; int num_tokens; num_tokens = parse_json(json, &tokens); if (num_tokens < 0) return -1; if (tokens[0].type != JSMN_OBJECT) { logit(LOG_ERR, "JSON response contained no objects."); goto cleanup; } if (check_success(json, tokens, num_tokens) == -1) { logit(LOG_ERR, "Request was unsuccessful."); goto cleanup; } for (int i = 1; i < num_tokens; i++) { if (jsoneq(json, tokens + i, key) != 0) continue; if (i < num_tokens - 1) { *out_result = tokens[i+1]; free(tokens); return 0; } } logit(LOG_INFO, "Could not find key '%s'.", key); cleanup: free(tokens); return -1; } static int json_copy_value(char *dest, size_t dest_size, const char *json, const jsmntok_t *token) { size_t length; if (token->type != JSMN_STRING) return -1; length = token->end - token->start + 1; if (length > dest_size) return -2; strlcpy(dest, json + token->start, length); return 0; } static int get_id(char *dest, size_t dest_size, const ddns_info_t *info, char *request, size_t request_len) { const char *body; http_trans_t trans; jsmntok_t id; http_t client; char *response_buf; size_t response_buflen = DDNS_HTTP_RESPONSE_BUFFER_SIZE; int rc = RC_OK; response_buf = calloc(response_buflen, sizeof(char)); if (!response_buf) return RC_OUT_OF_MEMORY; CHECK(http_construct(&client)); http_set_port(&client, info->server_name.port); http_set_remote_name(&client, info->server_name.name); client.ssl_enabled = info->ssl_enabled; CHECK(http_init(&client, "Id query")); trans.req = request; trans.req_len = request_len; trans.rsp = response_buf; trans.max_rsp_len = response_buflen - 1; /* Save place for a \0 at the end */ logit(LOG_DEBUG, "Request:\n%s", request); CHECK(http_transaction(&client, &trans)); http_exit(&client); http_destruct(&client, 1); logit(LOG_DEBUG, "Response:\n%s", trans.rsp); CHECK(check_response_code(trans.status)); body = trans.rsp_body; if (get_result_value(body, "id", &id) < 0) { rc = RC_DDNS_RSP_NOHOST; goto cleanup; } if (json_copy_value(dest, dest_size, body, &id) < 0) { logit(LOG_ERR, "Id did not fit into buffer."); rc = RC_BUFFER_OVERFLOW; } logit(LOG_DEBUG, "ID value: %s", dest); cleanup: free(response_buf); return rc; } static const char* get_record_type(const char *address) { if (strstr(address, ":")) return IPV6_RECORD_TYPE; return IPV4_RECORD_TYPE; } static int setup(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *hostname) { const char *record_type; struct cfdata *data; size_t len; const char *zone_name = info->creds.username; int rc = RC_OK; if (*zone_name == '\0' || !strchr(zone_name, '.')) { logit(LOG_ERR, "Invalid zone. Enter the Cloudflare zone in the username field."); return RC_DDNS_INVALID_OPTION; } data = calloc(1, sizeof(struct cfdata)); if (!data) return RC_OUT_OF_MEMORY; if (info->data) free(info->data); info->data = data; record_type = get_record_type(hostname->address); logit(LOG_DEBUG, "Zone: %s", zone_name); len = snprintf(ctx->request_buf, ctx->request_buflen, CLOUDFLARE_ZONE_ID_REQUEST, zone_name, info->user_agent, info->creds.password); if (len >= ctx->request_buflen) { logit(LOG_ERR, "Request for zone '%s' did not fit into buffer.", zone_name); return RC_BUFFER_OVERFLOW; } rc = get_id(data->zone_id, MAX_ID, info, ctx->request_buf, len); if (rc != RC_OK) { logit(LOG_ERR, "Zone '%s' not found.", zone_name); return rc; } logit(LOG_DEBUG, "Cloudflare Zone: '%s' Id: %s", zone_name, data->zone_id); len = snprintf(ctx->request_buf, ctx->request_buflen, CLOUDFLARE_HOSTNAME_ID_REQUEST, data->zone_id, record_type, hostname->name, info->user_agent, info->creds.password); if (len >= ctx->request_buflen) { logit(LOG_ERR, "Request for zone '%s', id %s did not fit into buffer.", zone_name, data->zone_id); return RC_BUFFER_OVERFLOW; } rc = get_id(data->hostname_id, MAX_ID, info, ctx->request_buf, ctx->request_buflen); if (rc == RC_OK) { logit(LOG_DEBUG, "Cloudflare Host: '%s' Id: %s", hostname->name, data->hostname_id); } else if (rc == RC_DDNS_RSP_NOHOST) { strcpy(data->hostname_id, ""); return RC_OK; } else { logit(LOG_INFO, "Hostname '%s' not found.", hostname->name); } return rc; } static int request(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *hostname) { const char *record_type; struct cfdata *data = (struct cfdata *)info->data; size_t content_len; char json_data[256]; record_type = get_record_type(hostname->address); content_len = snprintf(json_data, sizeof(json_data), CLOUDFLARE_UPDATE_JSON_FORMAT, record_type, hostname->name, hostname->address, info->ttl >= 0 ? info-> ttl : 1, // Time to live for DNS record. Value of 1 is 'automatic' info->proxied ? "true" : "false"); if (strlen(data->hostname_id) == 0) return snprintf(ctx->request_buf, ctx->request_buflen, CLOUDFLARE_HOSTNAME_CREATE_REQUEST, data->zone_id, info->user_agent, info->creds.password, content_len, json_data); return snprintf(ctx->request_buf, ctx->request_buflen, CLOUDFLARE_HOSTNAME_UPDATE_REQUEST, data->zone_id, data->hostname_id, info->user_agent, info->creds.password, content_len, json_data); } static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *hostname) { int rc; (void)info; (void)hostname; rc = check_response_code(trans->status); if (rc == RC_OK && check_success_only(trans->rsp_body) < 0) rc = RC_DDNS_RSP_NOTOK; return rc; } PLUGIN_INIT(plugin_init) { plugin_register(&plugin); } PLUGIN_EXIT(plugin_exit) { plugin_unregister(&plugin); } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/plugins/cloudxns.c000066400000000000000000000230611400562756000164770ustar00rootroot00000000000000/* Plugin for CloudXNS * * Copyright (C) 2017 Richard Yu * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include "md5.h" #include "plugin.h" /* cloudxns.net specific update request format */ #define CLOUDXNS_UPDATE_IP_REQUEST \ "PUT %s/%u " \ "HTTP/1.0\r\n" \ "Host: %s\r\n" \ "User-Agent: %s\r\n" \ "API-KEY: %s\r\n" \ "API-REQUEST-DATE: %s\r\n" \ "API-HMAC: %s\r\n" \ "Content-Length: %zu\r\n\r\n" \ "%s" #define CLOUDXNS_GET_REQUEST \ "GET %s HTTP/1.0\r\n" \ "Host: %s\r\n" \ "User-Agent: %s\r\n" \ "API-KEY: %s\r\n" \ "API-REQUEST-DATE: %s\r\n" \ "API-HMAC: %s\r\n\r\n" #define CLOUDXNS_UPDATE_PARAM_BODY \ "{\"domain_id\":\"%u\"," \ "\"host\":\"%s\"," \ "\"value\":\"%s\"}" #define MD5_DIGEST_BYTES 16 struct cx { unsigned int record_id; unsigned int domain_id; char date[30]; char hmac[MD5_DIGEST_BYTES * 2 + 1]; char body[256]; size_t len; }; struct http { ddns_t *ctx; ddns_info_t *info; char *response; /* pointer to ctx->work_buf */ }; static int setup (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int request (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int response (http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias); static ddns_system_t plugin = { .name = "default@cloudxns.net", .setup = (setup_fn_t)setup, .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = DYNDNS_MY_IP_SERVER, .checkip_url = DYNDNS_MY_CHECKIP_URL, .checkip_ssl = DYNDNS_MY_IP_SSL, .server_name = "www.cloudxns.net", .server_url = "/api2/record" }; /* http://stackoverflow.com/a/744822 TODO: Move to a separate file */ static int string_endswith(const char *str, const char *suffix) { size_t lenstr; size_t lensuffix; if (!str || !suffix) return 0; lenstr = strlen(str); lensuffix = strlen(suffix); if (lensuffix > lenstr) return 0; return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0; } static char *get_time(char *str, size_t len) { time_t rawtime; time(&rawtime); strftime(str, len, "%a %b %d %T %Y", localtime(&rawtime)); return str; } static void hmac(char *dst, size_t sz, char *fmt, ...) { unsigned char out[MD5_DIGEST_BYTES]; va_list ap; size_t i, len; char buf[256]; va_start(ap, fmt); len = vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); md5((unsigned char *)buf, len, out); memset(dst, 0, sz); for (i = 0; i < MD5_DIGEST_BYTES; i++) { char hex[3]; snprintf(hex, sizeof(hex), "%02x", out[i]); strlcat(dst, hex, sz); } } static int http_send(struct http *http, char *msg, char *fmt, ...) { http_trans_t trans; ddns_info_t *info; va_list ap; http_t client; ddns_t *ctx; int rc; info = http->info; ctx = http->ctx; va_start(ap, fmt); trans.req_len = vsnprintf(ctx->request_buf, ctx->request_buflen, fmt, ap); trans.req = ctx->request_buf; trans.rsp = ctx->work_buf; trans.max_rsp_len = ctx->work_buflen - 1; /* Save place for a \0 at the end */ va_end(ap); rc = http_construct(&client); if (rc) return rc; http_set_port(&client, info->server_name.port); http_set_remote_name(&client, info->server_name.name); client.ssl_enabled = info->ssl_enabled; rc = http_init(&client, msg); if (rc) goto err; rc = http_transaction(&client, &trans); http_exit(&client); err: http_destruct(&client, 1); if (rc) return rc; http->response = trans.rsp_body; return http_status_valid(trans.status); } /* * API_KEY = info->creds.username * SECRET_KEY = info->creds.password */ static int setup(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { struct http http = { ctx, info, NULL }; struct cx *cx; char str[MD5_DIGEST_BYTES * 2 + 1]; char buffer[256], domain[256], prefix[SERVER_NAME_LEN]; char *tmp, *item; size_t hostlen, domainlen; int rc = 0; if (!info->data) { info->data = malloc(sizeof(struct cx)); if (!info->data) return RC_OUT_OF_MEMORY; } cx = (struct cx *)info->data; memset(cx, 0, sizeof(struct cx)); get_time(cx->date, sizeof(cx->date)); /* HMAC=md5(API_KEY+URL+DATE+SECRET_KEY) */ hmac(str, sizeof(str), "%shttp%s://www.cloudxns.net/api2/domain%s%s", info->creds.username, info->ssl_enabled ? "s" : "", cx->date, info->creds.password); rc = http_send(&http, "Sending domain list query", CLOUDXNS_GET_REQUEST, "/api2/domain", info->server_name.name, info->user_agent, info->creds.username, cx->date, str); if (rc) { logit(LOG_WARNING, "Failed fetching domain list, rc: %d", rc); goto err; } /* * Example: with added whitespace and line breaks for clarity * { "code":1, "message":"Operate successfully", "total":"1", * "data": [{ * "id":"12345", "domain":"example.com.", "status":"ok", * "level":"3", "take_over_status":"Taken over", * "create_time":"2017-04-04 07:58:56", * "update_time":"2017-04-08 18:43:57", * "ttl":"600" * }] * } */ tmp = strchr(http.response, '['); if (!tmp) { rc = RC_DDNS_INVALID_OPTION; goto err; } for (item = tmp; item; item = strstr(item, ",{")) { unsigned int id; int num; item++; num = sscanf(item, "{\"id\":\"%u\",\"domain\":\"%255[^\"]", &id, domain); if (num == 2 && *domain) { domain[strlen(domain) - 1] = 0; /* Remove trailing dot */ if (string_endswith(alias->name, domain)) { cx->domain_id = id; break; } } } if (cx->domain_id == 0) { logit(LOG_ERR, "Hostname '%s' not found in domains list!", alias->name); rc = RC_DDNS_INVALID_OPTION; goto err; } logit(LOG_DEBUG, "CloudXNS Domain: '%s' ID: %u", domain, cx->domain_id); /* HMAC=md5(API_KEY+URL+DATE+SECRET_KEY) */ hmac(str, sizeof(str), "%shttp%s://www.cloudxns.net/api2/record/%u%s%s", info->creds.username, info->ssl_enabled ? "s" : "", cx->domain_id, cx->date, info->creds.password); snprintf(buffer, sizeof(buffer), "/api2/record/%u", cx->domain_id); rc = http_send(&http, "Sending records list query", CLOUDXNS_GET_REQUEST, buffer, info->server_name.name, info->user_agent, info->creds.username, cx->date, str); if (rc) { logit(LOG_WARNING, "Failed fetching record ID, rc: %d", rc); goto err; } tmp = strchr(http.response, '['); if (!tmp) { rc = RC_DDNS_INVALID_OPTION; goto err; } hostlen = strlen(alias->name); domainlen = strlen(domain); if (hostlen == domainlen) { prefix[0] = '@'; prefix[1] = 0; } else { size_t num = hostlen - domainlen - 1; if (num <= sizeof(prefix)) strlcpy(prefix, alias->name, num); } for (item = tmp; item; item = strstr(item, ",{")) { unsigned int id; char _prefix[64]; int num; item++; num = sscanf(item, "{\"record_id\":\"%u\",\"host_id\":\"%*d\",\"host\":\"%63[^\"]", &id, _prefix); if (num == 2 && *_prefix) { if (string_compare(prefix, _prefix)) { cx->record_id = id; break; } } } if (cx->record_id == 0) { logit(LOG_ERR, "Record '%s' not found in records list!", prefix); rc = RC_DDNS_INVALID_OPTION; goto err; } logit(LOG_DEBUG, "CloudXNS Record: '%s' ID: %u", prefix, cx->record_id); cx->len = snprintf(cx->body, sizeof(cx->body), CLOUDXNS_UPDATE_PARAM_BODY, cx->domain_id, prefix, alias->address); /* HMAC=md5(API_KEY+URL+PARAM_BODY+DATE+SECRET_KEY) */ hmac(cx->hmac, sizeof(cx->hmac), "%shttp%s://www.cloudxns.net/api2/record/%u%s%s%s", info->creds.username, info->ssl_enabled ? "s" : "", cx->record_id, cx->body, cx->date, info->creds.password); return 0; err: free(info->data); info->data = NULL; return rc; } static int request(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { struct cx *cx = (struct cx *)info->data; (void)alias; /* cx is filled in by setup() */ if (!cx) return -1; return snprintf(ctx->request_buf, ctx->request_buflen, CLOUDXNS_UPDATE_IP_REQUEST, info->server_url, cx->record_id, info->server_name.name, info->user_agent, info->creds.username, cx->date, cx->hmac, cx->len, cx->body); } /* * CloudXNS specific response validator. With added whitespace for * clarity: * { "code":1, "message":"success", * "data": { * "id":12345, "domain_name":"example.com.", * "value":"1.2.3.4","bak_data":"" * } * } * * We search our own IP address in response and that's enough. */ static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias) { char *resp = trans->rsp_body; (void)info; DO(http_status_valid(trans->status)); if (strstr(resp, alias->address)) return 0; return RC_DDNS_RSP_NOTOK; } PLUGIN_INIT(plugin_init) { plugin_register(&plugin); } PLUGIN_EXIT(plugin_exit) { plugin_unregister(&plugin); } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/plugins/common.c000066400000000000000000000053161400562756000161330ustar00rootroot00000000000000/* Common plugin methods, built around DynDNS standard HTTP API * * Copyright (C) 2003-2004 Narcis Ilisei * Copyright (C) 2006 Steve Horbachuk * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "plugin.h" /* * dyndns.org specific update address format * * Also applies to other dyndns2 api compatible services, like: * DNS-O-Matic, no-ip, 3322, HE and nsupdate.info. */ #define DYNDNS_UPDATE_IP_HTTP_REQUEST \ "GET %s?" \ "hostname=%s&" \ "myip=%s" \ "%s " \ "HTTP/1.0\r\n" \ "Host: %s\r\n" \ "Authorization: Basic %s\r\n" \ "User-Agent: %s\r\n\r\n" /* * DynDNS request composer -- common to many other DDNS providers as well */ int common_request(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { char wildcard[20] = ""; if (info->wildcard) strlcpy(wildcard, "&wildcard=ON", sizeof(wildcard)); return snprintf(ctx->request_buf, ctx->request_buflen, DYNDNS_UPDATE_IP_HTTP_REQUEST, info->server_url, alias->name, alias->address, wildcard, info->server_name.name, info->creds.encoded_password, info->user_agent); } /* * DynDNS response validator -- common to many other DDNS providers as well * 'good' or 'nochg' are the good answers, */ int common_response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias) { char *body = trans->rsp_body; (void)info; (void)alias; DO(http_status_valid(trans->status)); if (strstr(body, "good") || strstr(body, "nochg")) return 0; if (strstr(body, "dnserr") || strstr(body, "911")) return RC_DDNS_RSP_RETRY_LATER; if (strstr(body, "badauth")) return RC_DDNS_RSP_AUTH_FAIL; /* Loopia responds "[200 OK] nohost" when no DNS record exists */ if (strstr(body, "nohost")) return RC_DDNS_RSP_NOHOST; return RC_DDNS_RSP_NOTOK; } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/plugins/ddnss.c000066400000000000000000000045051400562756000157550ustar00rootroot00000000000000/* Plugin for ddnss.de * * Copyright (C) 2016 Sven Hoefer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "plugin.h" #define DDNSS_UPDATE_IP_REQUEST \ "GET %s?" \ "user=%s&" \ "pwd=%s&" \ "host=%s" \ " " \ "HTTP/1.0\r\n" \ "Host: %s\r\n" \ "User-Agent: %s\r\n\r\n" static int request (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int response (http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias); static ddns_system_t plugin = { .name = "default@ddnss.de", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = DYNDNS_MY_IP_SERVER, .checkip_url = DYNDNS_MY_CHECKIP_URL, .checkip_ssl = DYNDNS_MY_IP_SSL, .server_name = "ddnss.de", .server_url = "/upd.php" }; static int request(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { return snprintf(ctx->request_buf, ctx->request_buflen, DDNSS_UPDATE_IP_REQUEST, info->server_url, info->creds.username, info->creds.password, alias->name, info->server_name.name, info->user_agent); } static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias) { char *resp = trans->rsp_body; (void)info; (void)alias; DO(http_status_valid(trans->status)); if (strstr(resp, "Updated")) return 0; return RC_DDNS_RSP_NOTOK; } PLUGIN_INIT(plugin_init) { plugin_register(&plugin); } PLUGIN_EXIT(plugin_exit) { plugin_unregister(&plugin); } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/plugins/dhis.c000066400000000000000000000050201400562756000155620ustar00rootroot00000000000000/* Plugin for DHIS.org * * Copyright (C) 2011 Bryan Hoover * Copyright (C) 2014-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "plugin.h" /* * is.dhis.org specific update request format * https://dhis.org/WebEngine.ipo?context=dhis.website.updating */ #define DHIS_UPDATE_IP_REQUEST \ "GET %s" \ "hostname=%s&" \ "password=%s&" \ "ipaddr=%s&" \ "updatetimeout=0 " \ "HTTP/1.0\r\n" \ "Host: %s\r\n" \ "User-Agent: %s\r\n\r\n" static int request (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int response (http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias); static ddns_system_t plugin = { .name = "default@dhis.org", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = DYNDNS_MY_IP_SERVER, .checkip_url = DYNDNS_MY_CHECKIP_URL, .checkip_ssl = DYNDNS_MY_IP_SSL, .server_name = "is.dhis.org", .server_url = "/?" }; static int request(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { return snprintf(ctx->request_buf, ctx->request_buflen, DHIS_UPDATE_IP_REQUEST, info->server_url, alias->name, info->creds.password, alias->address, info->server_name.name, info->user_agent); } static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias) { char *rsp = trans->rsp_body; (void)info; (void)alias; DO(http_status_valid(trans->status)); if (strstr(rsp, alias->address)) return 0; return RC_DDNS_RSP_NOTOK; } PLUGIN_INIT(plugin_init) { plugin_register(&plugin); } PLUGIN_EXIT(plugin_exit) { plugin_unregister(&plugin); } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/plugins/dnsexit.c000066400000000000000000000051511400562756000163160ustar00rootroot00000000000000/* Inadyn dnsExit plugin * * Copyright (C) 2003-2004 Narcis Ilisei * Copyright (C) 2006 Steve Horbachuk * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "plugin.h" #define DNSEXIT_UPDATE_IP_HTTP_REQUEST \ "GET %s?" \ "login=%s&" \ "password=%s&" \ "host=%s&" \ "myip=%s " \ "HTTP/1.0\r\n" \ "Host: %s\r\n" \ "User-Agent: %s\r\n\r\n" static int request (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int response (http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias); static ddns_system_t plugin = { .name = "default@dnsexit.com", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = "ip.dnsexit.com", .checkip_url = "/", .server_name = "update.dnsexit.com", .server_url = "/RemoteUpdate.sv" }; static int request(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { return snprintf(ctx->request_buf, ctx->request_buflen, DNSEXIT_UPDATE_IP_HTTP_REQUEST, info->server_url, info->creds.username, info->creds.password, alias->name, alias->address, info->server_name.name, info->user_agent); } static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias) { int code = -1; char *tmp; (void)info; (void)alias; DO(http_status_valid(trans->status)); tmp = strstr(trans->rsp_body, "\n"); if (tmp) sscanf(++tmp, "%4d=", &code); switch (code) { case 0: case 1: return 0; case 4: case 11: return RC_DDNS_RSP_RETRY_LATER; default: break; } return RC_DDNS_RSP_NOTOK; } PLUGIN_INIT(plugin_init) { plugin_register(&plugin); } PLUGIN_EXIT(plugin_exit) { plugin_unregister(&plugin); } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/plugins/dnspod.c000066400000000000000000000156031400562756000161320ustar00rootroot00000000000000/* Plugin for DNSPod * * Copyright (C) 2017 Richard Yu * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "plugin.h" /* dnspod.cn specific update request format */ #define DNSPOD_API_REQUEST \ "POST /%s HTTP/1.0\r\n" \ "Host: %s\r\n" \ "User-Agent: %s\r\n" \ "Content-Length: %zu\r\n" \ "Content-Type: application/x-www-form-urlencoded\r\n\r\n" \ "%s" static int setup (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int request (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int response (http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias); static ddns_system_t plugin = { .name = "default@dnspod.cn", .setup = (setup_fn_t)setup, .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = DYNDNS_MY_IP_SERVER, .checkip_url = DYNDNS_MY_CHECKIP_URL, .checkip_ssl = DYNDNS_MY_IP_SSL, .server_name = "dnsapi.cn", .server_url = "" }; static int fetch_record_id(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias, char *domain, char *prefix) { http_trans_t trans; http_t client; char *tmp; char buffer[256]; int record_id = 0; int rc, len; (void)alias; /* login_token=API_ID,API_TOKEN */ len = snprintf(buffer, sizeof(buffer), "login_token=%s%%2C%s&format=json&domain=%s&length=1&sub_domain=%s", info->creds.username, info->creds.password, domain, prefix); if (len >= (int)sizeof(buffer)) return -RC_BUFFER_OVERFLOW; trans.req_len = snprintf(ctx->request_buf, ctx->request_buflen, DNSPOD_API_REQUEST, "Record.List", info->server_name.name, info->user_agent, strlen(buffer), buffer); trans.req = ctx->request_buf; trans.rsp = ctx->work_buf; trans.max_rsp_len = ctx->work_buflen - 1; /* Save place for a \0 at the end */ rc = http_construct(&client); if (rc) return -rc; http_set_port(&client, info->server_name.port); http_set_remote_name(&client, info->server_name.name); client.ssl_enabled = info->ssl_enabled; rc = http_init(&client, "Sending record list query"); if (rc) return -rc; rc = http_transaction(&client, &trans); logit(LOG_DEBUG, "=> %s", trans.rsp_body); http_exit(&client); http_destruct(&client, 1); if (rc || (rc = http_status_valid(trans.status))) { logit(LOG_WARNING, "Failed fetching record ID, rc: %d", rc); return -rc; } /* * Example: with added whitespace and line breaks for clarity *{ * "status": {"code": "1", "message": "Action completed successful", "created_at": "2017-06-28 14:36:28"}, * "domain": { * "id": "59753949", * "name": "example.org", * "punycode": "example.org", * "grade": "DP_Free", * "owner": "example@example.org", * "ext_status": "dnserror", * "ttl": 600, * "min_ttl": 600, * "dnspod_ns": ["f1g1ns1.dnspod.net", "f1g1ns2.dnspod.net"], * "status": "enable" * }, * "info": {"sub_domains": "3", "record_total": "3"}, * "records": [{ * "id": "306419640", * "ttl": "600", * "value": "1.2.3.4", * "enabled": "1", * "status": "enabled", * "updated_on": "2017-06-28 12:28:01", * "name": "@", * "line": "\u9ed8\u8ba4", * "line_id": "0", * "type": "A", * "weight": null, * "monitor_status": "", * "remark": "", * "use_aqb": "no", * "mx": "0" * }] *} */ tmp = strstr(trans.rsp_body, "[{"); if (tmp && 1 == sscanf(tmp, "[{\"id\":\"%d\"", &record_id)) return record_id; return -RC_DDNS_INVALID_OPTION; } /* * API_ID = info->creds.username * API_TOKEN = info->creds.password */ static int setup(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { char *tmp; char buffer[SERVER_NAME_LEN], domain[SERVER_NAME_LEN], prefix[SERVER_NAME_LEN]; int record_id; int len; strlcpy(buffer, alias->name, sizeof(buffer)); tmp = strchr(buffer, '.'); if (!tmp) return RC_DDNS_INVALID_OPTION; if (tmp[1] != 0 && strchr(tmp + 1, '.') != NULL) { *tmp++ = 0; strlcpy(domain, tmp, sizeof(domain)); strlcpy(prefix, buffer, sizeof(prefix)); } else { strlcpy(domain, alias->name, sizeof(domain)); strlcpy(prefix, "@", sizeof(prefix)); } record_id = fetch_record_id(ctx, info, alias, domain, prefix); if (record_id <= 0) { logit(LOG_ERR, "Record '%s' not found in records list!", prefix); if (record_id < 0) return -record_id; return RC_DDNS_INVALID_OPTION; } logit(LOG_DEBUG, "DNSPod Record: '%s' ID: %u", prefix, record_id); len = snprintf(buffer, sizeof(buffer), "login_token=%s%%2C%s&format=json&domain=%s&record_id=%d&record_line=%s&value=%s", info->creds.username, info->creds.password, domain, record_id, "%E9%BB%98%E8%AE%A4", alias->address); if (len >= (int)sizeof(buffer)) return RC_BUFFER_OVERFLOW; if (info->data) free(info->data); info->data = strdup(buffer); return 0; } static int request(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { size_t len; char *post; (void)alias; if (!info->data) return -RC_INVALID_POINTER; post = (char *)info->data; len = strlen(post); return snprintf(ctx->request_buf, ctx->request_buflen, DNSPOD_API_REQUEST, "Record.Ddns", info->server_name.name, info->user_agent, len, post); } /* * DNSPod specific response validator. With added whitespace for * clarity: *{ * "status": { * "code": "1", * "message": "Action completed successful", * "created_at": "2017-06-28 15:11:16" * }, * "record": { * "id": 306419640, * "name": "@", * "value": "1.2.3.4" * } *} * * We search our own IP address in response and that's enough. */ static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias) { char *resp = trans->rsp_body; (void)info; (void)alias; DO(http_status_valid(trans->status)); if (strstr(resp, alias->address)) return 0; return RC_DDNS_RSP_NOTOK; } PLUGIN_INIT(plugin_init) { plugin_register(&plugin); } PLUGIN_EXIT(plugin_exit) { plugin_unregister(&plugin); } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/plugins/duckdns.c000066400000000000000000000054411400562756000162750ustar00rootroot00000000000000/* Plugin for DuckDNS * * Copyright (C) 2010-2020 Joachim Nilsson * Copyright (C) 2014 Andy Padavan * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "plugin.h" /* * For API documentation we currently only have this * https://www.duckdns.org/install.jsp#linux-cron */ #define DUCKDNS_UPDATE_IP_HTTP_REQUEST \ "GET %s?" \ "domains=%s&" \ "token=%s&" \ "ip=%s " \ "HTTP/1.0\r\n" \ "Host: %s\r\n" \ "User-Agent: %s\r\n\r\n" static int request (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias); static ddns_system_t plugin = { .name = "default@duckdns.org", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = "ipv4.wtfismyip.com", .checkip_url = "/text", .server_name = "www.duckdns.org", .server_url = "/update" }; static int request(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { char name[SERVER_NAME_LEN], *p; /* Handle some.name.duckdns.org properly */ p = strstr(alias->name, "duckdns.org"); if (p) { size_t len = p - alias->name; if (len > sizeof(name)) len = sizeof(name); strlcpy(name, alias->name, len); } else { snprintf(name, sizeof(name), "%s", alias->name); } return snprintf(ctx->request_buf, ctx->request_buflen, DUCKDNS_UPDATE_IP_HTTP_REQUEST, info->server_url, name, info->creds.username, alias->address, info->server_name.name, info->user_agent); } static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias) { char *resp = trans->rsp_body; (void)info; (void)alias; DO(http_status_valid(trans->status)); if (strstr(resp, "OK") || strstr(resp, "good")) return RC_OK; return RC_DDNS_RSP_NOTOK; } PLUGIN_INIT(plugin_init) { plugin_register(&plugin); } PLUGIN_EXIT(plugin_exit) { plugin_unregister(&plugin); } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/plugins/duiadns.c000066400000000000000000000052021400562756000162640ustar00rootroot00000000000000/* Plugin for Duiadns * * Copyright (C) 2015 Duiadns, Co. www.duiadns.net * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "md5.h" #include "plugin.h" #define DUIADNS_UPDATE_IP_HTTP_REQUEST \ "GET %s?" \ "host=%s&" \ "password=%s&" \ "ip4=%s " \ "HTTP/1.0\r\n" \ "Host: %s\r\n" \ "User-Agent: %s\r\n\r\n" #define MD5_DIGEST_BYTES 16 static int request (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int response (http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias); static ddns_system_t plugin = { .name = "default@duiadns.net", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = "ipv4.duiadns.net", .checkip_url = "/", .server_name = "ipv4.duiadns.net", .server_url = "/dynamic.duia" }; static int request(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { int i; char digeststr[MD5_DIGEST_BYTES * 2 + 1] = {0}; unsigned char digestbuf[MD5_DIGEST_BYTES] = {0}; md5((unsigned char *)info->creds.password, strlen(info->creds.password), digestbuf); for (i = 0; i < MD5_DIGEST_BYTES; i++) sprintf(&digeststr[i * 2], "%02x", digestbuf[i]); return snprintf(ctx->request_buf, ctx->request_buflen, DUIADNS_UPDATE_IP_HTTP_REQUEST, info->server_url, alias->name, digeststr, alias->address, info->server_name.name, info->user_agent); } static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias) { char *resp = trans->rsp_body; (void)info; (void)alias; DO(http_status_valid(trans->status)); if (strstr(resp, "Hostname ")) return RC_OK; return RC_DDNS_RSP_NOTOK; } PLUGIN_INIT(plugin_init) { plugin_register(&plugin); } PLUGIN_EXIT(plugin_exit) { plugin_unregister(&plugin); } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/plugins/dyndns.c000066400000000000000000000163661400562756000161510ustar00rootroot00000000000000/* Plugin for DynDNS2 API compatible services * * Supported DDNS providers are: * - DynDNS, * - DNS-O-Matic, * - no-ip, * - 3322, * - Hurricane-Electric (HE) * - Loopia, and * - nsupdate.info * - Google Domains * - SPDYN * - Dynu * * Copyright (C) 2003-2004 Narcis Ilisei * Copyright (C) 2006 Steve Horbachuk * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "plugin.h" static int request (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int response (http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias); static ddns_system_t dyndns = { .name = "default@dyndns.org", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = DYNDNS_MY_IP_SERVER, .checkip_url = DYNDNS_MY_CHECKIP_URL, .checkip_ssl = DYNDNS_MY_IP_SSL, .server_name = "members.dyndns.org", .server_url = "/nic/update" }; static ddns_system_t dnsomatic = { .name = "default@dnsomatic.com", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = "myip.dnsomatic.com", .checkip_url = "/", .server_name = "updates.dnsomatic.com", .server_url = "/nic/update" }; /* Support HOSTNAME.selfhost.eu, see issue #215 */ static ddns_system_t selfhost = { .name = "default@selfhost.de", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = DYNDNS_MY_IP_SERVER, .checkip_url = DYNDNS_MY_CHECKIP_URL, .checkip_ssl = DYNDNS_MY_IP_SSL, .server_name = "carol.selfhost.de", .server_url = "/nic/update" }; static ddns_system_t no_ip = { .name = "default@no-ip.com", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = "ip1.dynupdate.no-ip.com", .checkip_url = "/", .checkip_ssl = DYNDNS_MY_IP_SSL, .server_name = "dynupdate.no-ip.com", .server_url = "/nic/update" }; static ddns_system_t noip = { .name = "default@noip.com", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = "ip1.dynupdate.noip.com", .checkip_url = "/", .checkip_ssl = DYNDNS_MY_IP_SSL, .server_name = "dynupdate.noip.com", .server_url = "/nic/update" }; /* http://www.pubyun.com/wiki/%E5%B8%AE%E5%8A%A9:api#%E6%8E%A5%E5%8F%A3%E5%9C%B0%E5%9D%80 */ static ddns_system_t _3322 = { .name = "dyndns@3322.org", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = "ip.3322.net", .checkip_url = "/", .server_name = "members.3322.org", .server_url = "/dyndns/update" }; /* See also tunnelbroker.c for Hurricate Electric's IPv6 service */ static ddns_system_t henet = { .name = "dyndns@he.net", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = "checkip.dns.he.net", .checkip_url = "/", .server_name = "dyn.dns.he.net", .server_url = "/nic/update" }; /* New API, see also the old compat plugin for Hurricane Electric's * IPv6 tunnel brokering service in tunnelbroker.c, and above. * For API details, see their forum posting at * https://forums.he.net/index.php?topic=3153.msg19774#msg19774 */ static ddns_system_t tunnelbroker = { .name = "default@tunnelbroker.net", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = DYNDNS_MY_IP_SERVER, .checkip_url = DYNDNS_MY_CHECKIP_URL, .checkip_ssl = DYNDNS_MY_IP_SSL, .server_name = "ipv4.tunnelbroker.net", .server_url = "/nic/update" }; /* * Securepoint DDNS service (SPDYN) * http://wiki.securepoint.de/index.php/SPDNS_FAQ */ static ddns_system_t spdyn = { .name = "default@spdyn.de", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = "checkip4.spdyn.de", .checkip_url = "/", .checkip_ssl = DDNS_CHECKIP_SSL_UNSUPPORTED, .server_name = "update.spdyn.de", .server_url = "/nic/update" }; /* Note: below is IPv4 only. ipv6.nsupdate.info would work IPv6 only. */ static ddns_system_t nsupdate_info_ipv4 = { .name = "ipv4@nsupdate.info", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = "ipv4.nsupdate.info", .checkip_url = "/myip", .server_name = "ipv4.nsupdate.info", .server_url = "/nic/update" }; /* * Loopia supports HTTPS, for details on supported variables, see * https://support.loopia.com/wiki/About_the_DynDNS_support */ static ddns_system_t loopia = { .name = "default@loopia.com", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = "dns.loopia.se", .checkip_url = "/checkip/checkip.php", .server_name = "dns.loopia.se", .server_url = "/XDynDNSServer/XDynDNS.php" }; static ddns_system_t googledomains = { .name = "default@domains.google.com", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = DYNDNS_MY_IP_SERVER, .checkip_url = DYNDNS_MY_CHECKIP_URL, .checkip_ssl = DYNDNS_MY_IP_SSL, .server_name = "domains.google.com", .server_url = "/nic/update" }; static ddns_system_t dynu = { .name = "default@dynu.com", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = "checkip.dynu.com", .checkip_url = "/", .server_name = "api.dynu.com", .server_url = "/nic/update" }; static int request(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { return common_request(ctx, info, alias); } static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias) { return common_response(trans, info, alias); } PLUGIN_INIT(plugin_init) { plugin_register(&dyndns); plugin_register(&dnsomatic); plugin_register(&selfhost); plugin_register(&no_ip); plugin_register(&noip); plugin_register(&_3322); plugin_register(&henet); plugin_register(&tunnelbroker); plugin_register(&spdyn); plugin_register(&nsupdate_info_ipv4); plugin_register(&loopia); plugin_register(&googledomains); plugin_register(&dynu); } PLUGIN_EXIT(plugin_exit) { plugin_unregister(&dyndns); plugin_unregister(&dnsomatic); plugin_unregister(&selfhost); plugin_unregister(&no_ip); plugin_unregister(&noip); plugin_unregister(&_3322); plugin_unregister(&henet); plugin_unregister(&tunnelbroker); plugin_unregister(&spdyn); plugin_unregister(&nsupdate_info_ipv4); plugin_unregister(&loopia); plugin_unregister(&googledomains); plugin_unregister(&dynu); } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/plugins/dynv6.c000066400000000000000000000056361400562756000157160ustar00rootroot00000000000000/* Plugin for dynv6.com * * Copyright (C) 2016 Sven Hoefer * Copyright (C) 2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "plugin.h" #define DYNV6_UPDATE_IP_REQUEST \ "GET %s?" \ "%s=auto&" \ "hostname=%s&" \ "token=%s" \ " " \ "HTTP/1.0\r\n" \ "Host: %s\r\n" \ "User-Agent: %s\r\n\r\n" static int request (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int response (http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias); static ddns_system_t plugin4 = { .name = "default@ipv4.dynv6.com", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = DYNDNS_MY_IP_SERVER, .checkip_url = DYNDNS_MY_CHECKIP_URL, .checkip_ssl = DYNDNS_MY_IP_SSL, .server_name = "ipv4.dynv6.com", .server_url = "/api/update" }; static ddns_system_t plugin6 = { .name = "default@dynv6.com", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = DYNDNS_MY_IP_SERVER, .checkip_url = DYNDNS_MY_CHECKIP_URL, .checkip_ssl = DYNDNS_MY_IP_SSL, .server_name = "dynv6.com", .server_url = "/api/update" }; static int request(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { const char *ver = "ipv6"; if (strstr(info->system->name, "ipv4")) ver = "ipv4"; return snprintf(ctx->request_buf, ctx->request_buflen, DYNV6_UPDATE_IP_REQUEST, info->server_url, ver, /* ipv6=auto, or ipv4=auto */ alias->name, info->creds.username, info->server_name.name, info->user_agent); } static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias) { char *resp = trans->rsp_body; (void)info; (void)alias; DO(http_status_valid(trans->status)); if (strstr(resp, "updated") || strstr(resp, "unchanged")) return 0; return RC_DDNS_RSP_NOTOK; } PLUGIN_INIT(plugin_init) { plugin_register(&plugin4); plugin_register(&plugin6); } PLUGIN_EXIT(plugin_exit) { plugin_unregister(&plugin4); plugin_unregister(&plugin6); } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/plugins/easydns.c000066400000000000000000000054141400562756000163100ustar00rootroot00000000000000/* Plugin for easyDNS * * Copyright (C) 2003-2004 Narcis Ilisei * Copyright (C) 2006 Steve Horbachuk * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "plugin.h" /* * For details, see the excellent support page at easyDNS * https://fusion.easydns.com/Knowledgebase/Article/View/102/0/dynamic-dns */ #define EASYDNS_UPDATE_IP_REQUEST \ "GET %s?" \ "hostname=%s&" \ "myip=%s&" \ "wildcard=%s " \ "HTTP/1.0\r\n" \ "Host: %s\r\n" \ "Authorization: Basic %s\r\n" \ "User-Agent: %s\r\n\r\n" static int request (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int response (http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias); static ddns_system_t plugin = { .name = "default@easydns.com", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = DYNDNS_MY_IP_SERVER, .checkip_url = DYNDNS_MY_CHECKIP_URL, .checkip_ssl = DYNDNS_MY_IP_SSL, .server_name = "api.cp.easydns.com", .server_url = "/dyn/generic.php" }; static int request(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { return snprintf(ctx->request_buf, ctx->request_buflen, EASYDNS_UPDATE_IP_REQUEST, info->server_url, alias->name, alias->address, info->wildcard ? "ON" : "OFF", info->server_name.name, info->creds.encoded_password, info->user_agent); } /* * NOERROR is the OK code here */ static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias) { char *resp = trans->rsp_body; (void)info; (void)alias; DO(http_status_valid(trans->status)); if (strstr(resp, "NOERROR")) return 0; if (strstr(resp, "TOOSOON")) return RC_DDNS_RSP_RETRY_LATER; return RC_DDNS_RSP_NOTOK; } PLUGIN_INIT(plugin_init) { plugin_register(&plugin); } PLUGIN_EXIT(plugin_exit) { plugin_unregister(&plugin); } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/plugins/freedns.c000066400000000000000000000123641400562756000162720ustar00rootroot00000000000000/* Plugin for FreeDNS * * Copyright (C) 2003-2004 Narcis Ilisei * Copyright (C) 2006 Steve Horbachuk * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "sha1.h" #include "plugin.h" /* freedns.afraid.org specific update request format */ #define FREEDNS_UPDATE_IP_REQUEST \ "GET %s?" \ "%s&" \ "address=%s " \ "HTTP/1.0\r\n" \ "Host: %s\r\n" \ "User-Agent: %s\r\n\r\n" #define SHA1_DIGEST_BYTES 20 static int setup (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int request (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int response (http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias); static ddns_system_t plugin = { .name = "default@freedns.afraid.org", .setup = (setup_fn_t)setup, .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = "freedns.afraid.org", .checkip_url = "/dynamic/check.php", .server_name = "freedns.afraid.org", .server_url = "/dynamic/update.php" }; static char *fetch_keys(ddns_t *ctx, ddns_info_t *info) { unsigned char digestbuf[SHA1_DIGEST_BYTES] = { 0 }; char digeststr[SHA1_DIGEST_BYTES * 2 + 1]; http_trans_t trans; http_t client; char buffer[384]; int i, rc; rc = (http_construct(&client)); if (rc) return NULL; http_set_port(&client, info->server_name.port); http_set_remote_name(&client, info->server_name.name); client.ssl_enabled = info->ssl_enabled; rc = http_init(&client, "Fetching account API key"); if (rc) return NULL; /* SHA1 hash of username and password */ snprintf(buffer, sizeof(buffer), "%s|%s", info->creds.username, info->creds.password); sha1((unsigned char *)buffer, strlen(buffer), digestbuf); for (i = 0; i < SHA1_DIGEST_BYTES; i++) sprintf(&digeststr[i * 2], "%02x", digestbuf[i]); snprintf(buffer, sizeof(buffer), "/api/?action=getdyndns&v=2&sha=%s", digeststr); trans.req_len = snprintf(ctx->request_buf, ctx->request_buflen, GENERIC_HTTP_REQUEST, buffer, info->server_name.name, info->user_agent); trans.req = ctx->request_buf; trans.rsp = ctx->work_buf; trans.max_rsp_len = ctx->work_buflen - 1; /* Save place for a \0 at the end */ rc = http_transaction(&client, &trans); logit(LOG_DEBUG, "=> %s", trans.rsp_body); http_exit(&client); http_destruct(&client, 1); if (rc || (rc = http_status_valid(trans.status))) { logit(LOG_DEBUG, "Failed fetching API key, rc: %d\n", rc); return NULL; } return strdup(trans.rsp_body); } /* FreeDNS requires an API key, the following code fetches yours */ static int setup(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { char *hash = NULL; #ifndef ENABLE_SIMULATION char host[256], updateurl[256]; char *buf, *tmp, *line; tmp = buf = fetch_keys(ctx, info); if (!buf) { logit(LOG_INFO, "Cannot find you FreeDNS account API keys"); return RC_ERROR; } for (line = strsep(&tmp, "\n"); line; line = strsep(&tmp, "\n")) { int num; num = sscanf(line, "%255[^|\r\n]|%*[^|\r\n]|%255[^|\r\n]", host, updateurl); if (*line && num == 2 && !strcmp(host, alias->name)) { hash = strstr(updateurl, "?"); break; } } free(buf); if (!hash) { logit(LOG_INFO, "Cannot find your DNS name in the list of API keys"); return 1; } hash++; #else hash = ""; #endif /* ENABLE_SIMULATION */ if (info->data) free(info->data); info->data = strdup(hash); return 0; } static int request(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { char *hash = (char *)info->data; if (!hash) return 0; return snprintf(ctx->request_buf, ctx->request_buflen, FREEDNS_UPDATE_IP_REQUEST, info->server_url, hash, alias->address, info->server_name.name, info->user_agent); } /* Freedns afraid.org.specific response validator: * * ok blabla and n.n.n.n * fail blabla and n.n.n.n * * are the good answers. We search our own IP address in response and * that's enough. */ static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias) { char *resp = trans->rsp_body; (void)info; (void)alias; DO(http_status_valid(trans->status)); if (strstr(resp, alias->address)) return 0; return RC_DDNS_RSP_NOTOK; } PLUGIN_INIT(plugin_init) { plugin_register(&plugin); } PLUGIN_EXIT(plugin_exit) { plugin_unregister(&plugin); } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/plugins/freemyip.c000066400000000000000000000045621400562756000164650ustar00rootroot00000000000000/* Plugin for FreeMyIP * * Copyright (C) 2017 Tomasz 'Cadence' Grabowski * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "plugin.h" /* * For API information, see https://freemyip.com/help * Maybe add support for "&myip=1.2.3.4"? */ #define FREEMYIP_UPDATE_IP_HTTP_REQUEST \ "GET %s?" \ "token=%s&" \ "domain=%s " \ "HTTP/1.0\r\n" \ "Host: %s\r\n" \ "User-Agent: %s\r\n\r\n" static int request (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias); static ddns_system_t plugin = { .name = "default@freemyip.com", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .nousername = 1, /* Provider does not require username */ .checkip_name = "ipv4.wtfismyip.com", .checkip_url = "/text", .server_name = "freemyip.com", .server_url = "/update" }; static int request(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { return snprintf(ctx->request_buf, ctx->request_buflen, FREEMYIP_UPDATE_IP_HTTP_REQUEST, info->server_url, info->creds.password, alias->name, info->server_name.name, info->user_agent); } static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias) { (void)info; (void)alias; DO(http_status_valid(trans->status)); if (strstr(trans->rsp_body, "OK")) return RC_OK; return RC_DDNS_RSP_NOTOK; } PLUGIN_INIT(plugin_init) { plugin_register(&plugin); } PLUGIN_EXIT(plugin_exit) { plugin_unregister(&plugin); } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/plugins/generic.c000066400000000000000000000146431400562756000162620ustar00rootroot00000000000000/* Generic DDNS plugin * * Copyright (C) 2003-2004 Narcis Ilisei * Copyright (C) 2006 Steve Horbachuk * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include "plugin.h" /* * Generic update format for sites that perform the update using: * * http://some.address.domain/somesubdir?some_param_name=ALIAS * * With the standard http stuff and basic base64 encoded auth. * The parameter here is the entire request, except the the alias. */ #define GENERIC_BASIC_AUTH_UPDATE_IP_REQUEST \ "GET %s%s " \ "HTTP/1.0\r\n" \ "Host: %s\r\n" \ "Authorization: Basic %s\r\n" \ "User-Agent: %s\r\n\r\n" char *generic_responses[] = { "OK", "good", "true", "updated", "nochg", NULL }; static int request (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int response (http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias); static ddns_system_t generic = { .name = "custom", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = DDNS_MY_IP_SERVER, .checkip_url = DDNS_MY_CHECKIP_URL, .checkip_ssl = DDNS_MY_IP_SSL, .server_name = "", .server_url = "" }; /* Replace %? with @str */ static void replace_fmt(char *fmt, char *str, size_t fmtlen) { char *src = fmt + fmtlen; size_t len = strlen(str); memmove(fmt + len, src, strlen(src) + 1); memcpy(fmt, str, strlen(str)); } /* Skip %? if it has not been specified */ static void skip_fmt(char *fmt, size_t len) { char *src = fmt + len; memmove(fmt, src, strlen(src) + 1); } /* * Fully custom server URL, with % format specifiers * * %u - username * %p - password, if HTTP basic auth is not used * %h - hostname * %i - IP address */ static int custom_server_url(ddns_info_t *info, ddns_alias_t *alias) { char *ptr; while ((ptr = strchr(info->server_url, '%'))) { if (!strncmp(ptr, "%u", 2)) { if (strnlen(info->creds.username, USERNAME_LEN) <= 0) { logit(LOG_ERR, "Format specifier in ddns-path used: '%%u'," " but 'username' configuration option has not been specified!"); skip_fmt(ptr, 2); } else { replace_fmt(ptr, info->creds.username, 2); } continue; } if (!strncmp(ptr, "%p", 2)) { if (strnlen(info->creds.password, PASSWORD_LEN) <= 0) { logit(LOG_ERR, "Format specifier in ddns-path used: '%%p'," " but 'password' configuration option has not been specified!"); skip_fmt(ptr, 2); } else { replace_fmt(ptr, info->creds.password, 2); } continue; } if (!strncmp(ptr, "%h", 2)) { replace_fmt(ptr, alias->name, 2); continue; } if (!strncmp(ptr, "%i", 2)) { replace_fmt(ptr, alias->address, 2); continue; } /* NOTE: This should be the last one */ if (!strncmp(ptr, "%%", 2)) { replace_fmt(ptr, "%", 2); continue; } logit(LOG_ERR, "Unknown format specifier in ddns-path: '%c'", ptr[1]); return -1; } return strlen(info->server_url); } static char tohex(char code) { static char hex[] = "0123456789abcdef"; return hex[code & 15]; } /* Used to check if user already URL encoded */ static int ishex(char *str) { if (strlen(str) < 3) return 0; if (str[0] == '%' && isxdigit(str[1]) && isxdigit(str[2])) return 1; return 0; } /* * Simple URL encoder, with exceptions for /, ?, =, and &, which should * usually be encoded as well, but are here exposed raw to advanced * end-users. */ static char *url_encode(char *str) { char *buf, *ptr; buf = calloc(strlen(str) * 3 + 1, sizeof(char)); if (!buf) return NULL; ptr = buf; while (str[0]) { char ch = str[0]; if (ishex(str)) { *ptr++ = *str++; *ptr++ = *str++; *ptr++ = *str++; continue; } if (isalnum(ch) || ch == '-' || ch == '_' || ch == '.' || ch == '~') *ptr++ = ch; else if (ch == '/' || ch == '?' || ch == '&' || ch == '=') *ptr++ = ch; else if (ch == ' ') *ptr++ = '+'; else *ptr++ = '%', *ptr++ = tohex(ch >> 4), *ptr++ = tohex(ch & 15); str++; } *ptr = '\0'; return buf; } /* * This function is called for every listed hostname alias in the * custom{} section. There is currently no way to only call it * once, in case a DDNS provider supports many hostnames in the * HTTP GET URL. */ static int request(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { int ret; char *url; char *arg = ""; /* * if the user has specified modifiers, then he is probably * aware of how to append his hostname or IP, otherwise just * append the hostname or ip (depending on the append_myip option) */ if (strchr(info->server_url, '%')) { if (custom_server_url(info, alias) <= 0) logit(LOG_ERR, "Invalid server URL: %s", info->server_url); } else { /* Backwards compat, default to append hostname */ arg = alias->name; if (info->append_myip) arg = alias->address; } url = url_encode(info->server_url); if (!url) return 0; ret = snprintf(ctx->request_buf, ctx->request_buflen, GENERIC_BASIC_AUTH_UPDATE_IP_REQUEST, url, arg, info->server_name.name, info->creds.encoded_password, info->user_agent); free(url); return ret; } static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias) { char *resp = trans->rsp_body; size_t i; (void)info; (void)alias; DO(http_status_valid(trans->status)); for (i = 0; i < info->server_response_num; i++) { if (strcasestr(resp, info->server_response[i])) return 0; } return RC_DDNS_RSP_NOTOK; } PLUGIN_INIT(plugin_init) { plugin_register(&generic); } PLUGIN_EXIT(plugin_exit) { plugin_unregister(&generic); } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/plugins/giradns.c000066400000000000000000000044331400562756000162710ustar00rootroot00000000000000/* Plugin for GiraDNS * * Copyright (C) 2015 Thorsten Mühlfelder * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "plugin.h" #define GIRADNS_UPDATE_IP_HTTP_REQUEST \ "GET %s?" \ "u=%s&" \ "p=%s&" \ "ip=%s " \ "HTTP/1.0\r\n" \ "Host: %s\r\n" \ "User-Agent: %s\r\n\r\n" static int request (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias); static ddns_system_t plugin = { .name = "default@gira.de", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = "ipv4.wtfismyip.com", .checkip_url = "/text", .server_name = "homeserver.gira.de", .server_url = "/hsdyndns.php" }; static int request(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { return snprintf(ctx->request_buf, ctx->request_buflen, GIRADNS_UPDATE_IP_HTTP_REQUEST, info->server_url, info->creds.username, info->creds.password, alias->address, info->server_name.name, info->user_agent); } static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias) { char *resp = trans->rsp_body; (void)info; (void)alias; DO(http_status_valid(trans->status)); if (strstr(resp, "OK")) return RC_OK; return RC_DDNS_RSP_NOTOK; } PLUGIN_INIT(plugin_init) { plugin_register(&plugin); } PLUGIN_EXIT(plugin_exit) { plugin_unregister(&plugin); } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/plugins/sitelutions.c000066400000000000000000000051611400562756000172230ustar00rootroot00000000000000/* Plugin for Sitelutions * * Copyright (C) 2003-2004 Narcis Ilisei * Copyright (C) 2006 Steve Horbachuk * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "plugin.h" /* sitelutions.com specific update address format */ #define SITELUTIONS_UPDATE_IP_HTTP_REQUEST \ "GET %s?" \ "user=%s&" \ "pass=%s&" \ "id=%s&" \ "ip=%s " \ "HTTP/1.0\r\n" \ "Host: %s\r\n" \ "User-Agent: %s\r\n\r\n" static int request (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int response (http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias); static ddns_system_t plugin = { .name = "default@sitelutions.com", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = DYNDNS_MY_IP_SERVER, .checkip_url = DYNDNS_MY_CHECKIP_URL, .checkip_ssl = DYNDNS_MY_IP_SSL, .server_name = "www.sitelutions.com", .server_url = "/dnsup" }; static int request(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { return snprintf(ctx->request_buf, ctx->request_buflen, SITELUTIONS_UPDATE_IP_HTTP_REQUEST, info->server_url, info->creds.username, info->creds.password, alias->name, alias->address, info->server_name.name, info->user_agent); } static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias) { char *resp = trans->rsp_body; (void)info; (void)alias; DO(http_status_valid(trans->status)); if (strstr(resp, "success")) return 0; if (strstr(resp, "dberror")) return RC_DDNS_RSP_RETRY_LATER; return RC_DDNS_RSP_NOTOK; } PLUGIN_INIT(plugin_init) { plugin_register(&plugin); } PLUGIN_EXIT(plugin_exit) { plugin_unregister(&plugin); } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/plugins/tunnelbroker.c000066400000000000000000000060711400562756000173540ustar00rootroot00000000000000/* Plugin for Hurricate Electric's IPv6 service * * Copyright (C) 2003-2004 Narcis Ilisei * Copyright (C) 2006 Steve Horbachuk * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "md5.h" #include "plugin.h" /* HE tunnelbroker.com specific update request format */ #define HE_IPV6TB_UPDATE_IP_REQUEST \ "GET %s?" \ "ip=%s&" \ "apikey=%s&" \ "pass=%s&" \ "tid=%s " \ "HTTP/1.0\r\n" \ "Host: %s\r\n" \ "User-Agent: %s\r\n\r\n" #define MD5_DIGEST_BYTES 16 static int request (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int response (http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias); static ddns_system_t plugin = { .name = "ipv6tb@he.net", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = "checkip.dns.he.net", .checkip_url = "/", .server_name = "ipv4.tunnelbroker.net", .server_url = "/ipv4_end.php" }; static int request(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { int i; char digeststr[MD5_DIGEST_BYTES * 2 + 1]; unsigned char digestbuf[MD5_DIGEST_BYTES]; md5((unsigned char *)info->creds.password, strlen(info->creds.password), digestbuf); for (i = 0; i < MD5_DIGEST_BYTES; i++) sprintf(&digeststr[i * 2], "%02x", digestbuf[i]); return snprintf(ctx->request_buf, ctx->request_buflen, HE_IPV6TB_UPDATE_IP_REQUEST, info->server_url, alias->address, info->creds.username, digeststr, alias->name, info->server_name.name, info->user_agent); } /* * Hurricate Electric IPv6 tunnelbroker specific response validator * Own IP address and 'already in use' are the good answers. */ static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias) { char *resp = trans->rsp_body; (void)info; (void)alias; DO(http_status_valid(trans->status)); if (strstr(resp, alias->address) || strstr(resp, "-ERROR: This tunnel is already associated with this IP address.")) return 0; return RC_DDNS_RSP_NOTOK; } PLUGIN_INIT(plugin_init) { plugin_register(&plugin); } PLUGIN_EXIT(plugin_exit) { plugin_unregister(&plugin); } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/plugins/yandex.c000066400000000000000000000200101400562756000161170ustar00rootroot00000000000000/* Plugin for Yandex PDD (Yandex.Connect) * * Copyright (C) 2017 https://github.com/dmitrodem * Copyright (C) 2019 Timur Birsh * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "plugin.h" #include "json.h" #define YANDEX_GET_REQUEST \ "GET %s " \ "HTTP/1.1\r\n" \ "Host: %s\r\n" \ "PddToken: %s\r\n" \ "User-Agent: %s\r\n\r\n" #define YANDEX_POST_REQUEST \ "POST %s " \ "HTTP/1.1\r\n" \ "Host: %s\r\n" \ "PddToken: %s\r\n" \ "User-Agent: %s\r\n" \ "Content-Length: %i\r\n" \ "Content-Type: application/x-www-form-urlencoded\r\n\r\n" \ "%s" /* XXX: please increase if not enough */ #define TOKENS_EXPECTED 4096 struct yandex { char url[512]; int len; int record_id; }; static int setup (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int request (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int response (http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias); static ddns_system_t plugin = { .name = "default@pdd.yandex.ru", .setup = (setup_fn_t)setup, .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = DYNDNS_MY_IP_SERVER, .checkip_url = DYNDNS_MY_CHECKIP_URL, .checkip_ssl = DYNDNS_MY_IP_SSL, .server_name = "pddimp.yandex.ru:443", .server_url = "/dynamic/update.php" }; /* FIXME: remove and use parse_json() instead */ static jsmntok_t *get_tokens(const char *response, int *n) { jsmn_parser *p; jsmntok_t *t; int r; p = malloc(sizeof(*p)); if (!p) { logit(LOG_ERR, "Not enough memory"); return NULL; } t = malloc(sizeof(*t) * TOKENS_EXPECTED); if (!t) { logit(LOG_ERR, "Not enough memory"); free(p); return NULL; } jsmn_init(p); r = jsmn_parse(p, response, strlen(response), t, TOKENS_EXPECTED); free(p); *n = r; if (r < 0) { logit(LOG_ERR, "Failed to parse JSON"); free(t); return NULL; } if ((r < 1) || (t[0].type != JSMN_OBJECT)) { logit(LOG_ERR, "JSON object expected"); free(t); return NULL; } return t; } static int success(const char *response) { jsmntok_t *t; int n, i; int rc = 0; t = get_tokens(response, &n); if (!t) return 0; for (i = 1; i < n - 1; i++) { jsmntok_t *tok = &t[i]; if (jsoneq(response, tok, "success")) continue; if (jsoneq(response, tok + 1, "ok") == 0) { rc = 1; break; } } free(t); return rc; } static int get_record_id(const char *response, const char *subdomain) { jsmntok_t *t; int n, i; int record_id = 0; int id_keyword_found = 0; enum { ST_UNKNOWN, ST_FIND_RECORDS, ST_FIND_RECORD_ID } state = ST_UNKNOWN; enum { SUBDOMAIN_NONE, SUBDOMAIN_KEYWORD, SUBDOMAIN_VALUE } subdomain_field = SUBDOMAIN_NONE; enum { TYPE_NONE, TYPE_KEYWORD, TYPE_VALUE } type_field = TYPE_NONE; t = get_tokens(response, &n); if (!t) return -1; for (i = 1; i < n; i++) { jsmntok_t *tok = &t[i]; switch (tok->type) { case JSMN_STRING: case JSMN_PRIMITIVE: if (jsoneq(response, tok, "records") == 0) { state = ST_FIND_RECORDS; break; } if (state != ST_FIND_RECORD_ID) break; if (jsoneq(response, tok, "subdomain") == 0) { subdomain_field = SUBDOMAIN_KEYWORD; break; } if (jsoneq(response, tok, "type") == 0) { type_field = TYPE_KEYWORD; break; } if (jsoneq(response, tok, "record_id") == 0) { id_keyword_found = 1; break; } if ((subdomain_field == SUBDOMAIN_KEYWORD) && (jsoneq(response, tok, subdomain)) == 0) subdomain_field = SUBDOMAIN_VALUE; if ((type_field == TYPE_KEYWORD) && (jsoneq(response, tok, "A")) == 0) type_field = TYPE_VALUE; if (id_keyword_found) { char buf[129]; // additional byte for \0 size_t n = tok->end - tok->start; id_keyword_found = 0; if (n > sizeof(buf) - 1) break; memset(buf, 0, sizeof(buf)); strncpy(buf, response + tok->start, n); record_id = strtol(buf, NULL, 10); } if (subdomain_field == SUBDOMAIN_VALUE && type_field == TYPE_VALUE && record_id > 0) { free(t); return record_id; } break; case JSMN_ARRAY: if (state != ST_FIND_RECORDS) break; state = ST_FIND_RECORD_ID; break; case JSMN_OBJECT: if (state != ST_FIND_RECORD_ID) break; subdomain_field = SUBDOMAIN_NONE; type_field = TYPE_NONE; id_keyword_found = 0; break; case JSMN_UNDEFINED: break; } } free(t); if (state != ST_FIND_RECORD_ID) { logit(LOG_ERR, "Got JSON document that cannot understand\n"); return -1; } return 0; } static int setup(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { struct yandex *y; http_trans_t trans; http_t client; char *resp; int rc = 0; if (!info->data) { info->data = malloc(sizeof(struct yandex)); if (!info->data) return RC_OUT_OF_MEMORY; } y = (struct yandex *)info->data; memset(y, 0, sizeof(struct yandex)); rc = http_construct(&client); if (rc) return rc; http_set_port(&client, info->server_name.port); http_set_remote_name(&client, info->server_name.name); client.ssl_enabled = info->ssl_enabled; rc = http_init(&client, "Sending records list query"); if (rc) { http_destruct(&client, 1); return rc; } snprintf(y->url, sizeof(y->url), "/api2/admin/dns/list?domain=%s", info->creds.username); trans.req_len = snprintf(ctx->request_buf, ctx->request_buflen, YANDEX_GET_REQUEST, y->url, info->server_name.name, info->creds.password, info->user_agent); trans.req = ctx->request_buf; trans.rsp = ctx->work_buf; trans.max_rsp_len = ctx->work_buflen - 1; rc = http_transaction(&client, &trans); http_exit(&client); http_destruct(&client, 1); if (rc || (rc = http_status_valid(trans.status))) { logit(LOG_WARNING, "Failed fetching record_id, rc: %d", rc); return rc; } resp = trans.rsp_body; logit(LOG_DEBUG, "Yandex response: %s", resp); if (!success(resp)) return RC_DDNS_INVALID_OPTION; y->record_id = get_record_id(resp, alias->name); if (y->record_id < 0) return RC_DDNS_INVALID_OPTION; if (y->record_id > 0) { logit(LOG_INFO, "Updating record, id = %i", y->record_id); y->len = snprintf(y->url, sizeof(y->url), "domain=%s&record_id=%i&subdomain=%s&content=%s", info->creds.username, y->record_id, alias->name, alias->address); } else { logit(LOG_INFO, "Creating record"); y->len = snprintf(y->url, sizeof(y->url), "domain=%s&type=A&subdomain=%s&content=%s", info->creds.username, alias->name, alias->address); } return 0; } static int request(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { struct yandex *y = (struct yandex *)info->data; (void)alias; if (!y) return -1; return snprintf(ctx->request_buf, ctx->request_buflen, YANDEX_POST_REQUEST, y->record_id > 0 ? "/api2/admin/dns/edit" : "/api2/admin/dns/add", info->server_name.name, info->creds.password, info->user_agent, y->len, y->url); } static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias) { char *resp = trans->rsp_body; (void)info; (void)alias; DO(http_status_valid(trans->status)); if (success(resp)) return 0; return RC_DDNS_RSP_NOTOK; } PLUGIN_INIT(plugin_init) { plugin_register(&plugin); } PLUGIN_EXIT(plugin_exit) { plugin_unregister(&plugin); } inadyn-2.8.1/plugins/zoneedit.c000066400000000000000000000052061400562756000164620ustar00rootroot00000000000000/* Plugin for ZoneEdit * * Copyright (C) 2003-2004 Narcis Ilisei * Copyright (C) 2006 Steve Horbachuk * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "plugin.h" #define ZONEEDIT_UPDATE_IP_REQUEST \ "GET %s?" \ "host=%s&" \ "dnsto=%s " \ "HTTP/1.0\r\n" \ "Host: %s\r\n" \ "Authorization: Basic %s\r\n" \ "User-Agent: %s\r\n\r\n" static int request (ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias); static int response (http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias); static ddns_system_t plugin = { .name = "default@zoneedit.com", .request = (req_fn_t)request, .response = (rsp_fn_t)response, .checkip_name = "dynamic.zoneedit.com", .checkip_url = "/checkip.html", .server_name = "dynamic.zoneedit.com", .server_url = "/auth/dynamic.html" }; static int request(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias) { return snprintf(ctx->request_buf, ctx->request_buflen, ZONEEDIT_UPDATE_IP_REQUEST, info->server_url, alias->name, alias->address, info->server_name.name, info->creds.encoded_password, info->user_agent); } /* * ZoneEdit OK codes are: * CODE=200, 201 * CODE=707, for duplicated updates */ static int response(http_trans_t *trans, ddns_info_t *info, ddns_alias_t *alias) { int code = -1; (void)info; (void)alias; DO(http_status_valid(trans->status)); sscanf(trans->rsp_body, "%*s CODE=\"%4d\" ", &code); switch (code) { case 200: case 201: case 707: /* XXX: is 707 really OK? */ return 0; default: break; } return RC_DDNS_RSP_NOTOK; } PLUGIN_INIT(plugin_init) { plugin_register(&plugin); } PLUGIN_EXIT(plugin_exit) { plugin_unregister(&plugin); } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/src/000077500000000000000000000000001400562756000136005ustar00rootroot00000000000000inadyn-2.8.1/src/Makefile.am000066400000000000000000000030561400562756000156400ustar00rootroot00000000000000AUTOMAKE_OPTIONS = subdir-objects AM_CPPFLAGS = -I$(top_srcdir)/include -DSYSCONFDIR=\"@sysconfdir@\" AM_CPPFLAGS += -DLOCALSTATEDIR=\"@localstatedir@\" -DRUNSTATEDIR=\"@runstatedir@\" AM_CPPFLAGS += -D_GNU_SOURCE -D_BSD_SOURCE -D_DEFAULT_SOURCE AM_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99 sbin_PROGRAMS = inadyn inadyn_SOURCES = main.c ddns.c cache.c \ error.c conf.c os.c \ http.c plugin.c tcp.c \ sha1.c base64.c \ json.c jsmn.c log.c \ makepath.c md5.c inadyn_CFLAGS = $(confuse_CFLAGS) $(OpenSSL_CFLAGS) $(GnuTLS_CFLAGS) inadyn_LDADD = $(confuse_LIBS) $(OpenSSL_LIBS) $(GnuTLS_LIBS) inadyn_LDADD += $(LIBS) $(LIBOBJS) if ENABLE_SSL if ENABLE_OPENSSL inadyn_SOURCES += openssl.c else inadyn_SOURCES += gnutls.c endif endif ## Plugins are currently built-in, and built from this directory instead ## of where they reside. They should be built by plugins/Makefile.am ## and be installed into $libdir/inadyn/plugins/ as *.so files inadyn_SOURCES += ../plugins/common.c ../plugins/changeip.c \ ../plugins/cloudflare.c ../plugins/cloudxns.c \ ../plugins/ddnss.c ../plugins/dhis.c \ ../plugins/dnsexit.c ../plugins/dnspod.c \ ../plugins/duckdns.c ../plugins/duiadns.c \ ../plugins/dyndns.c ../plugins/dynv6.c \ ../plugins/easydns.c ../plugins/freedns.c \ ../plugins/freemyip.c ../plugins/generic.c \ ../plugins/giradns.c \ ../plugins/sitelutions.c ../plugins/tunnelbroker.c \ ../plugins/yandex.c ../plugins/zoneedit.c inadyn-2.8.1/src/base64.c000066400000000000000000000114641400562756000150360ustar00rootroot00000000000000/* * RFC 1521 base64 encoding/decoding * * Copyright (C) 2006-2013, Brainspark B.V. * * This file is part of PolarSSL (http://www.polarssl.org) * Lead Maintainer: Paul Bakker * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "base64.h" static const unsigned char base64_enc_map[64] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; static const unsigned char base64_dec_map[128] = { 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 62, 127, 127, 127, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 127, 127, 127, 64, 127, 127, 127, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 127, 127, 127, 127, 127, 127, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 127, 127, 127, 127, 127 }; /* * Encode a buffer into base64 format */ int base64_encode( unsigned char *dst, size_t *dlen, const unsigned char *src, size_t slen ) { size_t i, n; int C1, C2, C3; unsigned char *p; if( slen == 0 ) return( 0 ); n = (slen << 3) / 6; switch( (slen << 3) - (n * 6) ) { case 2: n += 3; break; case 4: n += 2; break; default: break; } if( *dlen < n + 1 ) { *dlen = n + 1; return( ERR_BASE64_BUFFER_TOO_SMALL ); } n = (slen / 3) * 3; for( i = 0, p = dst; i < n; i += 3 ) { C1 = *src++; C2 = *src++; C3 = *src++; *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F]; *p++ = base64_enc_map[C3 & 0x3F]; } if( i < slen ) { C1 = *src++; C2 = ((i + 1) < slen) ? *src++ : 0; *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; if( (i + 1) < slen ) *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F]; else *p++ = '='; *p++ = '='; } *dlen = p - dst; *p = 0; return( 0 ); } /* * Decode a base64-formatted buffer */ int base64_decode( unsigned char *dst, size_t *dlen, const unsigned char *src, size_t slen ) { size_t i, n; uint32_t j, x; unsigned char *p; for( i = n = j = 0; i < slen; i++ ) { if( ( slen - i ) >= 2 && src[i] == '\r' && src[i + 1] == '\n' ) continue; if( src[i] == '\n' ) continue; if( src[i] == '=' && ++j > 2 ) return( ERR_BASE64_INVALID_CHARACTER ); if( src[i] > 127 || base64_dec_map[src[i]] == 127 ) return( ERR_BASE64_INVALID_CHARACTER ); if( base64_dec_map[src[i]] < 64 && j != 0 ) return( ERR_BASE64_INVALID_CHARACTER ); n++; } if( n == 0 ) return( 0 ); n = ((n * 6) + 7) >> 3; if( dst == NULL || *dlen < n ) { *dlen = n; return( ERR_BASE64_BUFFER_TOO_SMALL ); } for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ ) { if( *src == '\r' || *src == '\n' ) continue; j -= ( base64_dec_map[*src] == 64 ); x = (x << 6) | ( base64_dec_map[*src] & 0x3F ); if( ++n == 4 ) { n = 0; if( j > 0 ) *p++ = (unsigned char)( x >> 16 ); if( j > 1 ) *p++ = (unsigned char)( x >> 8 ); if( j > 2 ) *p++ = (unsigned char)( x ); } } *dlen = p - dst; return( 0 ); } inadyn-2.8.1/src/cache.c000066400000000000000000000127471400562756000150220ustar00rootroot00000000000000/* Reads and updates cache files * * Copyright (C) 2003-2004 Narcis Ilisei * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ /* * A user may have several DNS records to update. Earlier versions of * inadyn supports this, but only recorded changes in one cache file. * This made keeping track of update times per record impossible. Now * inadyn records each DNS entry to be updated in its own cache file, * enabling individual updates and tracking the file MTIME better. * * At startup inadyn will fall back to the old cache file and remove it * once it has read the IP and the modification time. */ #include #include #include #include #include #include "ddns.h" #include "cache.h" extern ddns_info_t *conf_info_iterator(int first); static int nslookup(ddns_alias_t *alias) { int error; struct addrinfo hints; struct addrinfo *result; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; /* IPv4 */ hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ hints.ai_flags = 0; hints.ai_protocol = 0; /* Any protocol */ error = getaddrinfo(alias->name, NULL, &hints, &result); if (!error) { char address[MAX_ADDRESS_LEN]; /* DNS reply for alias found, convert to IP# */ if (!getnameinfo(result->ai_addr, result->ai_addrlen, address, sizeof(address), NULL, 0, NI_NUMERICHOST)) { /* Update local record for next checkip call. */ alias->last_update = 0; strlcpy(alias->address, address, sizeof(alias->address)); logit(LOG_INFO, "Resolving hostname %s => IP# %s", alias->name, address); } freeaddrinfo(result); return 0; } logit(LOG_WARNING, "Failed resolving hostname %s: %s", alias->name, gai_strerror(error)); return 1; } static void read_one(ddns_alias_t *alias, int nonslookup) { FILE *fp; char path[256]; alias->last_update = 0; memset(alias->address, 0, sizeof(alias->address)); cache_file(alias->name, path, sizeof(path)); fp = fopen(path, "r"); if (!fp) { /* Exception for dnsomatic's special global hostname */ if (nonslookup || !strncmp(alias->name, "all.dnsomatic.com", sizeof(alias->name))) return; /* Try a DNS lookup of our last known IP#. */ nslookup(alias); } else { struct stat st; char address[MAX_ADDRESS_LEN]; if (fgets(address, sizeof(address), fp)) { logit(LOG_INFO, "Cached IP# %s for %s from previous invocation.", address, alias->name); strlcpy(alias->address, address, sizeof(alias->address)); } /* Initialize time since last update from modification time of cache file. */ if (!fstat(fileno(fp), &st)) { alias->last_update = st.st_mtime; logit(LOG_INFO, "Last update of %s on %s", alias->name, ctime(&st.st_mtime)); } fclose(fp); } } char *cache_file(char *name, char *buf, size_t len) { if (!buf || !name) return NULL; if (snprintf(buf, len, "%s/%s.cache", cache_dir, name) >= (int)len) logit(LOG_WARNING, "Too long name for buffer: '%s/' + '%s' + '.cache'", cache_dir, name); return buf; } /* * At boot, or when restarting inadyn at runtime, the memory struct holding our * current IP# is empty. We want to avoid unnecessary updates of our DDNS server * record, since we might get locked out for abuse, so we "seed" each of the DDNS * records of our struct with the cached IP# from our cache file, or from a regular * DNS query. */ int read_cache_file(ddns_t *ctx) { ddns_info_t *info; /* * Clear DNS cache before querying for the IP below, this to * prevent any artefacts from, e.g., nscd, which is a known * problem with DDNS clients. */ res_init(); if (!ctx) return RC_INVALID_POINTER; info = conf_info_iterator(1); while (info) { /* XXX: Possibly move this exception to each plugin */ const char *except[] = { "ipv6tb@he.net", "default@tunnelbroker.net" }; const char *name = info->system->name; size_t i, j; int nonslookup = 0; /* Exceptions -- no name to lookup */ for (i = 0; i < NELEMS(except); i++) { if (!strncmp(name, except[i], strlen(name))) { nonslookup = 1; break; } } // XXX: TODO better plugin identifiction here for (j = 0; j < info->alias_count; j++) read_one(&info->alias[j], nonslookup); info = conf_info_iterator(0); } return 0; } /* * Update cache with new IP * /var/cache/inadyn/my.server.name.cache { LAST-IPADDR } MTIME */ int write_cache_file(ddns_alias_t *alias) { FILE *fp; char path[256]; cache_file(alias->name, path, sizeof(path)); fp = fopen(path, "w"); if (fp) { logit(LOG_NOTICE, "Updating cache for %s", alias->name); fprintf(fp, "%s", alias->address); fclose(fp); return 0; } return 1; } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/src/conf.c000066400000000000000000000437551400562756000147070ustar00rootroot00000000000000/* libConfuse interface to parse inadyn.conf v2 format * * Copyright (C) 2014-2020 Joachim Nilsson * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include "cache.h" #include "ddns.h" #include "ssl.h" /* * period = 600 * forced-update = 604800 * * provider default@freedns.afraid.org * { * wildcard = false * username = example * password = secret * hostname = { "example.homenet.org", "example.afraid.org" } * } * * provider default@dyndns.org * { * ssl = true * username = admin * password = supersecret * hostname = example.dyndns.org * } */ static LIST_HEAD(head, di) info_list = LIST_HEAD_INITIALIZER(info_list); static void conf_errfunc(cfg_t *cfg, const char *format, va_list args) { char fmt[80]; if (cfg && cfg->filename && cfg->line) snprintf(fmt, sizeof(fmt), "%s:%d: %s", cfg->filename, cfg->line, format); else if (cfg && cfg->filename) snprintf(fmt, sizeof(fmt), "%s: %s", cfg->filename, format); else snprintf(fmt, sizeof(fmt), "%s", format); vlogit(LOG_ERR, fmt, args); } /* * Convert deprecated 'alias' setting to new 'hostname', * same functionality with new name. */ static int deprecate_alias(cfg_t *cfg) { size_t i; cfg_opt_t *alias, *hostname; alias = cfg_getopt(cfg, "alias"); if (!alias || cfg_opt_size(alias) <= 0) return 0; hostname = cfg_getopt(cfg, "hostname"); if (cfg_opt_size(hostname) > 0) { cfg_error(cfg, "Both 'hostname' and 'alias' set, cannot convert deprecated 'alias' to 'hostname'"); return -1; } cfg_error(cfg, "converting 'alias' to 'hostname'."); for (i = 0; i < cfg_opt_size(alias); i++) cfg_opt_setnstr(hostname, cfg_opt_getnstr(alias, i), i); cfg_free_value(alias); return 0; } static int validate_period(cfg_t *cfg, cfg_opt_t *opt) { int val = cfg_getint(cfg, opt->name); if (val < DDNS_MIN_PERIOD) cfg_setint(cfg, opt->name, DDNS_MIN_PERIOD); if (val > DDNS_MAX_PERIOD) cfg_setint(cfg, opt->name, DDNS_MAX_PERIOD); return 0; } static int validate_hostname(cfg_t *cfg, const char *provider, cfg_opt_t *hostname) { size_t i; if (!hostname) { cfg_error(cfg, "DDNS hostname setting is missing in provider %s", provider); return -1; } if (!cfg_opt_size(hostname)) { cfg_error(cfg, "No hostnames listed in DDNS provider %s", provider); return -1; } for (i = 0; i < cfg_opt_size(hostname); i++) { char *name = cfg_opt_getnstr(hostname, i); ddns_info_t info; if (sizeof(info.alias[0].name) < strlen(name)) { cfg_error(cfg, "Too long DDNS hostname (%s) in provider %s", name, provider); return -1; } } if (i >= DDNS_MAX_ALIAS_NUMBER) { cfg_error(cfg, "Too many hostname aliases, MAX %d supported!", DDNS_MAX_ALIAS_NUMBER); return -1; } return 0; } /* No need to validate username/password for custom providers */ static int validate_common(cfg_t *cfg, const char *provider, int custom) { ddns_system_t *ds; ds = plugin_find(provider, 0); if (!ds) { ds = plugin_find(provider, 1); if (!ds) { cfg_error(cfg, "Invalid DDNS provider %s", provider); return -1; } } if (!custom) { if (!ds->nousername && !cfg_getstr(cfg, "username")) { cfg_error(cfg, "Missing username setting for DDNS provider %s", provider); return -1; } if (!cfg_getstr(cfg, "password")) { cfg_error(cfg, "Missing password setting for DDNS provider %s", provider); return -1; } } return deprecate_alias(cfg) || validate_hostname(cfg, provider, cfg_getopt(cfg, "hostname")); } static int validate_provider(cfg_t *cfg, cfg_opt_t *opt) { const char *provider; cfg = cfg_opt_getnsec(opt, cfg_opt_size(opt) - 1); provider = cfg_title(cfg); if (!provider) { cfg_error(cfg, "Missing DDNS provider name"); return -1; } return validate_common(cfg, provider, 0); } static int validate_custom(cfg_t *cfg, cfg_opt_t *opt) { cfg = cfg_opt_getnsec(opt, cfg_opt_size(opt) - 1); if (!cfg) return -1; if (!cfg_getstr(cfg, "ddns-server")) { cfg_error(cfg, "Missing 'ddns-server' for custom DDNS provider"); return -1; } return validate_common(cfg, "custom", 1); } /* server:port => server:80 if port is not given */ static int getserver(const char *server, ddns_name_t *name) { char *str, *ptr; if (strlen(server) > sizeof(name->name)) return 1; str = strdup(server); if (!str) return 1; ptr = strchr(str, ':'); if (ptr) { *ptr++ = 0; name->port = atonum(ptr); if (-1 == name->port) name->port = HTTP_DEFAULT_PORT; } else { name->port = HTTP_DEFAULT_PORT; } strlcpy(name->name, str, sizeof(name->name)); free(str); return 0; } static int cfg_getserver(cfg_t *cfg, char *server, ddns_name_t *name) { const char *str; str = cfg_getstr(cfg, server); if (!str) return 1; return getserver(str, name); } #if 0 /* TODO: Move to a separate file */ #define string_startswith(string, prefix) strncasecmp(string, prefix, strlen(prefix)) == 0 static int parseproxy(const char *proxy, tcp_proxy_type_t *type, ddns_name_t *name) { int ret = 0; char *tmp, *str, *host, *protocol; int len; tmp = str = strdup(proxy); do { tmp = strstr(str, "://"); if (tmp) { host = tmp + 3; if (string_startswith(str, "socks5h")) *type = PROXY_SOCKS5_HOSTNAME; else if (string_startswith(str, "socks5")) *type = PROXY_SOCKS5; else if (string_startswith(str, "socks4a")) *type = PROXY_SOCKS4A; else if (string_startswith(str, "socks4") || string_startswith(str, "socks")) *type = PROXY_SOCKS4; else { len = tmp - str; protocol = malloc(len + 2); strncpy(protocol, str, len); protocol[len + 1] = 0; logit(LOG_ERR, "Unsupported proxy protocol '%s'.", protocol); free(protocol); ret = 1; break; } tmp = strchr(host, ':'); if (tmp) { *tmp++ = 0; name->port = atonum(tmp); if (-1 == name->port) { logit(LOG_ERR, "Invalid proxy port."); ret = 1; break; } strlcpy(name->name, host, sizeof(name->name)); } else { logit(LOG_ERR, "No proxy port is specified."); ret = 1; break; } } else { /* Currently we do not support http proxy. */ // *type = PROXY_HTTP; // logit(LOG_WARNING, "No proxy protocol is specified, use http proxy."); logit(LOG_WARNING, "No proxy protocol is specified."); ret = 1; break; } } while (0); free(str); return ret; } static int cfg_parseproxy(cfg_t *cfg, char *server, tcp_proxy_type_t *type, ddns_name_t *name) { const char *str; str = cfg_getstr(cfg, server); if (!str) return 1; return parseproxy(str, type, name); } #endif static int set_provider_opts(cfg_t *cfg, ddns_info_t *info, int custom) { ddns_system_t *system; const char *str; size_t j; if (custom) str = "custom"; else str = cfg_title(cfg); system = plugin_find(str, 0); if (!system) { system = plugin_find(str, 1); if (!system) { logit(LOG_ERR, "Cannot find an DDNS plugin for provider '%s'", str); return 1; } logit(LOG_WARNING, "Guessing DDNS plugin '%s' from '%s'", system->name, str); } info->system = system; if (getserver(system->checkip_name, &info->checkip_name)) goto error; if (strlen(system->checkip_url) > sizeof(info->checkip_url)) goto error; strlcpy(info->checkip_url, system->checkip_url, sizeof(info->checkip_url)); if (getserver(system->server_name, &info->server_name)) goto error; if (strlen(system->server_url) > sizeof(info->server_url)) goto error; strlcpy(info->server_url, system->server_url, sizeof(info->server_url)); info->wildcard = cfg_getbool(cfg, "wildcard"); info->ttl = cfg_getint(cfg, "ttl"); info->proxied = cfg_getbool(cfg, "proxied"); info->ssl_enabled = cfg_getbool(cfg, "ssl"); str = cfg_getstr(cfg, "username"); if (str && strlen(str) <= sizeof(info->creds.username)) strlcpy(info->creds.username, str, sizeof(info->creds.username)); str = cfg_getstr(cfg, "password"); if (str && strlen(str) <= sizeof(info->creds.password)) strlcpy(info->creds.password, str, sizeof(info->creds.password)); for (j = 0; j < cfg_size(cfg, "hostname"); j++) { size_t pos = info->alias_count; str = cfg_getnstr(cfg, "hostname", j); if (!str) continue; if (info->alias_count == DDNS_MAX_ALIAS_NUMBER) { logit(LOG_WARNING, "Too many hostname aliases, skipping %s ...", str); continue; } strlcpy(info->alias[pos].name, str, sizeof(info->alias[pos].name)); info->alias_count++; } if (custom) { info->append_myip = cfg_getbool(cfg, "append-myip"); cfg_getserver(cfg, "ddns-server", &info->server_name); str = cfg_getstr(cfg, "ddns-path"); if (str && strlen(str) <= sizeof(info->server_url)) strlcpy(info->server_url, str, sizeof(info->server_url)); for (j = 0; j < cfg_size(cfg, "ddns-response"); j++) { size_t pos = info->server_response_num; str = cfg_getnstr(cfg, "ddns-response", j); if (!str) continue; if (info->server_response_num >= NELEMS(info->server_response)) { logit(LOG_WARNING, "Skipping response '%s', only %zu custom responses supported", str, NELEMS(info->server_response)); continue; } strlcpy(info->server_response[pos], str, sizeof(info->server_response[pos])); info->server_response_num++; } /* Default check, if no configured custom response string(s) */ if (!cfg_size(cfg, "ddns-response")) { for (j = 0; j < NELEMS(info->server_response); j++) { if (!generic_responses[j]) break; strlcpy(info->server_response[j], generic_responses[j], sizeof(info->server_response[j])); info->server_response_num++; } } } /* * Follows the ssl setting by default, except for providers * known to NOT support HTTPS for their checkip servers. * * This setting may only be disabled by the user, with the * custom provider section being the exeception to the rule. */ info->checkip_ssl = info->ssl_enabled; /* Check known status of checkip server for provider */ switch (system->checkip_ssl) { case DDNS_CHECKIP_SSL_UNSUPPORTED: info->checkip_ssl = 0; break; case DDNS_CHECKIP_SSL_REQUIRED: info->checkip_ssl = 1; break; default: case DDNS_CHECKIP_SSL_SUPPORTED: if (!cfg_getbool(cfg, "checkip-ssl")) info->checkip_ssl = 0; } /* The checkip server can be set for all provider types */ if (!cfg_getserver(cfg, "checkip-server", &info->checkip_name)) { str = cfg_getstr(cfg, "checkip-path"); if (str && strlen(str) <= sizeof(info->checkip_url)) strlcpy(info->checkip_url, str, sizeof(info->checkip_url)); else strlcpy(info->checkip_url, "/", sizeof(info->checkip_url)); if (!strcasecmp(info->checkip_name.name, "default")) { strlcpy(info->checkip_name.name, DDNS_MY_IP_SERVER, sizeof(info->checkip_name.name)); strlcpy(info->checkip_url, "/", sizeof(info->checkip_url)); /* let local checkip-ssl decide HTTP/HTTPS for ipify */ } /* * If a custom checkip server is defined, the * checkip-ssl setting is fully honored. */ info->checkip_ssl = cfg_getbool(cfg, "checkip-ssl"); } /* The checkip-command overrides any default or custom checkip-server */ str = cfg_getstr(cfg, "checkip-command"); if (str && strlen(str) > 0) info->checkip_cmd = strdup(str); else if (script_cmd) info->checkip_cmd = strdup(script_cmd); /* The per-provider user-agent setting, defaults to the global setting */ info->user_agent = cfg_getstr(cfg, "user-agent"); if (!info->user_agent) info->user_agent = user_agent; /* A per-proivder optional proxy server:port */ #if 0 cfg_parseproxy(cfg, "proxy", &info->proxy_type, &info->proxy_name); #endif return 0; error: logit(LOG_ERR, "Failed setting up %s DDNS provider, skipping.", str); return 1; } static int create_provider(cfg_t *cfg, int custom) { ddns_info_t *info; info = calloc(1, sizeof(*info)); if (!info) { logit(LOG_ERR, "Failed allocating memory for provider %s", cfg_title(cfg)); return 1; } http_construct(&info->checkip); http_construct(&info->server); if (set_provider_opts(cfg, info, custom)) { free(info); return 1; } LIST_INSERT_HEAD(&info_list, info, link); return 0; } ddns_info_t *conf_info_iterator(int first) { static ddns_info_t *ptr = NULL; if (first) { ptr = LIST_FIRST(&info_list); return ptr; } if (!ptr || ptr == LIST_END(&info_list)) return NULL; ptr = LIST_NEXT(ptr, link); return ptr; } void conf_info_cleanup(void) { ddns_info_t *ptr, *tmp; LIST_FOREACH_SAFE(ptr, &info_list, link, tmp) { if (ptr->creds.encoded_password) free(ptr->creds.encoded_password); if (ptr->checkip_cmd) free(ptr->checkip_cmd); if (ptr->data) free(ptr->data); LIST_REMOVE(ptr, link); free(ptr); } } cfg_t *conf_parse_file(char *file, ddns_t *ctx) { int ret = 0; size_t i; cfg_opt_t provider_opts[] = { CFG_STR ("username", NULL, CFGF_NONE), CFG_STR ("password", NULL, CFGF_NONE), CFG_STR_LIST("hostname", NULL, CFGF_NONE), CFG_STR_LIST("alias", NULL, CFGF_DEPRECATED), CFG_BOOL ("ssl", cfg_true, CFGF_NONE), CFG_BOOL ("wildcard", cfg_false, CFGF_NONE), CFG_INT ("ttl", -1, CFGF_NODEFAULT), CFG_BOOL ("proxied", cfg_false, CFGF_NONE), CFG_STR ("checkip-server", NULL, CFGF_NONE), /* Syntax: name:port */ CFG_STR ("checkip-path", NULL, CFGF_NONE), /* Default: "/" */ CFG_BOOL ("checkip-ssl", cfg_true, CFGF_NONE), CFG_STR ("checkip-command",NULL, CFGF_NONE), /* Syntax: /path/to/cmd [args] */ CFG_STR ("user-agent", NULL, CFGF_NONE), // CFG_STR ("proxy", NULL, CFGF_NONE), /* Syntax: name:port */ CFG_END() }; cfg_opt_t custom_opts[] = { /* Same as a general provider */ CFG_STR ("username", NULL, CFGF_NONE), CFG_STR ("password", NULL, CFGF_NONE), CFG_STR_LIST("hostname", NULL, CFGF_NONE), CFG_STR_LIST("alias", NULL, CFGF_DEPRECATED), CFG_BOOL ("ssl", cfg_true, CFGF_NONE), CFG_BOOL ("wildcard", cfg_false, CFGF_NONE), CFG_INT ("ttl", -1, CFGF_NODEFAULT), CFG_BOOL ("proxied", cfg_false, CFGF_NONE), CFG_STR ("checkip-server", NULL, CFGF_NONE), /* Syntax: name:port */ CFG_STR ("checkip-path", NULL, CFGF_NONE), /* Default: "/" */ CFG_BOOL ("checkip-ssl", cfg_true, CFGF_NONE), CFG_STR ("checkip-command",NULL, CFGF_NONE), /* Syntax: /path/to/cmd [args] */ CFG_STR ("user-agent", NULL, CFGF_NONE), // CFG_STR ("proxy", NULL, CFGF_NONE), /* Syntax: name:port */ /* Custom settings */ CFG_BOOL ("append-myip", cfg_false, CFGF_NONE), CFG_STR ("ddns-server", NULL, CFGF_NONE), CFG_STR ("ddns-path", NULL, CFGF_NONE), CFG_STR_LIST("ddns-response", NULL, CFGF_NONE), CFG_END() }; cfg_opt_t opts[] = { CFG_BOOL("verify-address", cfg_true, CFGF_NONE), CFG_BOOL("fake-address", cfg_false, CFGF_NONE), CFG_BOOL("allow-ipv6", cfg_false, CFGF_NONE), CFG_BOOL("secure-ssl", cfg_true, CFGF_NONE), CFG_BOOL("broken-rtc", cfg_false, CFGF_NONE), CFG_STR ("ca-trust-file", NULL, CFGF_NONE), CFG_STR ("cache-dir", NULL, CFGF_DEPRECATED | CFGF_DROP), CFG_INT ("period", DDNS_DEFAULT_PERIOD, CFGF_NONE), CFG_INT ("iterations", DDNS_DEFAULT_ITERATIONS, CFGF_NONE), CFG_INT ("forced-update", DDNS_FORCED_UPDATE_PERIOD, CFGF_NONE), CFG_STR ("iface", NULL, CFGF_NONE), CFG_STR ("user-agent", NULL, CFGF_NONE), CFG_SEC ("provider", provider_opts, CFGF_MULTI | CFGF_TITLE), CFG_SEC ("custom", custom_opts, CFGF_MULTI | CFGF_TITLE), CFG_END() }; cfg_t *cfg; cfg = cfg_init(opts, CFGF_NONE); if (!cfg) { logit(LOG_ERR, "Failed initializing configuration file parser: %s", strerror(errno)); return NULL; } /* Custom logging, rather than default Confuse stderr logging */ cfg_set_error_function(cfg, conf_errfunc); /* Validators */ cfg_set_validate_func(cfg, "period", validate_period); cfg_set_validate_func(cfg, "provider", validate_provider); cfg_set_validate_func(cfg, "custom", validate_custom); switch (cfg_parse(cfg, file)) { case CFG_FILE_ERROR: logit(LOG_ERR, "Cannot read configuration file %s", file); return NULL; case CFG_PARSE_ERROR: logit(LOG_ERR, "Parse error in %s", file); return NULL; case CFG_SUCCESS: break; } /* Set global options */ ctx->normal_update_period_sec = cfg_getint(cfg, "period"); ctx->error_update_period_sec = DDNS_ERROR_UPDATE_PERIOD; ctx->forced_update_period_sec = cfg_getint(cfg, "forced-update"); if (once) ctx->total_iterations = 1; else ctx->total_iterations = cfg_getint(cfg, "iterations"); verify_addr = cfg_getbool(cfg, "verify-address"); ctx->forced_update_fake_addr = cfg_getbool(cfg, "fake-address"); /* Command line --iface=IFNAME takes precedence */ if (!use_iface) iface = cfg_getstr(cfg, "iface"); user_agent = cfg_getstr(cfg, "user-agent"); if (!user_agent) user_agent = DDNS_USER_AGENT; allow_ipv6 = cfg_getbool(cfg, "allow-ipv6"); secure_ssl = cfg_getbool(cfg, "secure-ssl"); broken_rtc = cfg_getbool(cfg, "broken-rtc"); ca_trust_file = cfg_getstr(cfg, "ca-trust-file"); if (ca_trust_file && !fexist(ca_trust_file)) { logit(LOG_ERR, "Cannot find CA trust file %s", ca_trust_file); return NULL; } for (i = 0; i < cfg_size(cfg, "provider"); i++) ret |= create_provider(cfg_getnsec(cfg, "provider", i), 0); for (i = 0; i < cfg_size(cfg, "custom"); i++) ret |= create_provider(cfg_getnsec(cfg, "custom", i), 1); if (ret) return NULL; return cfg; } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/src/ddns.c000066400000000000000000000655621400562756000147120ustar00rootroot00000000000000/* DDNS client updater main implementation file * * Copyright (C) 2003-2004 Narcis Ilisei * Copyright (C) 2006 Steve Horbachuk * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ddns.h" #include "cache.h" #include "log.h" #include "base64.h" #include "md5.h" #include "sha1.h" /* Conversation with the checkip server */ #define DYNDNS_CHECKIP_HTTP_REQUEST \ "GET %s HTTP/1.0\r\n" \ "Host: %s\r\n" \ "User-Agent: %s\r\n\r\n" /* Used to preserve values during reset at SIGHUP. Time also initialized from cache file at startup. */ static int cached_num_iterations = 0; extern ddns_info_t *conf_info_iterator(int first); static int wait_for_cmd(ddns_t *ctx) { int counter; ddns_cmd_t old_cmd; if (!ctx) return RC_INVALID_POINTER; old_cmd = ctx->cmd; if (old_cmd != NO_CMD) return 0; counter = ctx->update_period / ctx->cmd_check_period; while (counter--) { if (ctx->cmd != old_cmd) break; sleep(ctx->cmd_check_period); } return 0; } static int shell_transaction(ddns_t *ctx, ddns_info_t *info, const char *cmd) { FILE *pipe; int rc = 0; snprintf(ctx->request_buf, ctx->request_buflen, "INADYN_PROVIDER=\"%s\" INADYN_USER=\"%s\" %s", info->system->name, info->creds.username, cmd); logit(LOG_DEBUG, "Starting command to get my public IP#: %s", ctx->request_buf); pipe = popen(ctx->request_buf, "r"); if (!pipe) { logit(LOG_ERR, "Cannot run '%s': %s", ctx->request_buf, strerror(errno)); return errno; } /* TODO: timeout on fread */ rc = fread(ctx->work_buf, 1, ctx->work_buflen, pipe); if (rc < 0) { logit(LOG_ERR, "Error running '%s': %s", ctx->request_buf, strerror(errno)); ctx->work_buf[0] = 0; rc = errno; } else if (rc == 0) { logit(LOG_ERR, "Error running '%s': 0 bytes read", ctx->request_buf); ctx->work_buf[0] = 0; rc = RC_INVALID_POINTER; } else { logit(LOG_DEBUG, "Command '%s' returns %d bytes", ctx->request_buf, rc); ctx->work_buf[rc] = 0; rc = 0; } pclose(pipe); return rc; } static int get_req_for_ip_server(ddns_t *ctx, ddns_info_t *info) { return snprintf(ctx->request_buf, ctx->request_buflen, DYNDNS_CHECKIP_HTTP_REQUEST, info->checkip_url, info->checkip_name.name, info->user_agent); } /* * Send req to IP server and get the response */ static int server_transaction(ddns_t *ctx, ddns_info_t *provider) { int rc = 0; http_t *client; http_trans_t *trans; if (!provider) { logit(LOG_ERR, "Cannot query our address, invalid DDNS provider data!"); return RC_INVALID_POINTER; } client = &provider->checkip; client->ssl_enabled = provider->checkip_ssl; DO(http_init(client, "Checking for IP# change")); /* Prepare request for IP server */ memset(ctx->work_buf, 0, ctx->work_buflen); memset(ctx->request_buf, 0, ctx->request_buflen); memset(&ctx->http_transaction, 0, sizeof(ctx->http_transaction)); trans = &ctx->http_transaction; trans->req_len = get_req_for_ip_server(ctx, provider); trans->req = ctx->request_buf; trans->rsp = ctx->work_buf; trans->max_rsp_len = ctx->work_buflen - 1; /* Save place for terminating \0 in string. */ logit(LOG_DEBUG, "Querying DDNS checkip server for my public IP#: %s", ctx->request_buf); rc = http_transaction(client, &ctx->http_transaction); if (trans->status != 200) rc = RC_DDNS_INVALID_CHECKIP_RSP; http_exit(client); logit(LOG_DEBUG, "Server response: %s", trans->rsp); logit(LOG_DEBUG, "Checked my IP, return code %d: %s", rc, error_str(rc)); return rc; } /* * IP address validator, discards empty, local, loopback and other * globally invalid addresses */ static int is_address_valid(int family, const char *host) { /* * cloudflare would return requested hostname before client's ip address * block cloudflare ips so that https://1.1.1.1/cdn-cgi/trace would work * even if 1.1.1.1 is the first ip in the response body */ const char *except[] = { "1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001", "1.1.1.2", "1.0.0.2", "2606:4700:4700::1112", "2606:4700:4700::1002", "1.1.1.3", "1.0.0.3", "2606:4700:4700::1113", "2606:4700:4700::1003", "2606:4700:4700::64", "2606:4700:4700::6400" }; for (size_t i = 0; i < NELEMS(except); i++) { if (!strncmp(host, except[i], strlen(host))) { return 0; } } if (!verify_addr) { logit(LOG_DEBUG, "IP address validation disabled, %s is thus valid.", host); return 1; } if (family == AF_INET) { in_addr_t addr; struct in_addr address; logit(LOG_DEBUG, "Checking IPv4 address %s ...", host); if (!inet_pton(family, host, &address)) goto error; addr = ntohl(address.s_addr); if (IN_ZERONET(addr) || IN_LOOPBACK(addr) || IN_LINKLOCAL(addr) || IN_MULTICAST(addr) || IN_EXPERIMENTAL(addr)) goto error; logit(LOG_DEBUG, "IPv4 address %s is valid.", host); return 1; } if (!allow_ipv6) { logit(LOG_INFO, "IPv6 address disallowed, enable with 'allow-ipv6 = true'"); return 0; } if (family == AF_INET6) { struct in6_addr address, *addr = &address; logit(LOG_DEBUG, "Checking IPv6 address %s ...", host); if (!inet_pton(family, host, &address)) goto error; if (IN6_IS_ADDR_UNSPECIFIED(addr) || IN6_IS_ADDR_LOOPBACK(addr) || IN6_IS_ADDR_LINKLOCAL(addr) || IN6_IS_ADDR_SITELOCAL(addr)) goto error; logit(LOG_DEBUG, "IPv6 address %s is valid.", host); return 1; } error: logit(LOG_WARNING, "IP%s address %s is not a valid Internet address.", family == AF_INET ? "v4" : family == AF_INET6 ? "v6" : "", host); return 0; } static int parse_ipv4_address(char *buffer, char *address, size_t len) { int found = 0; char *accept = "0123456789."; char *needle, *haystack, *end; struct in_addr addr; haystack = buffer; needle = haystack; end = haystack + strlen(haystack) - 1; while (needle && haystack < end) { char ch; size_t num = 0; needle = strpbrk(haystack, accept); if (needle) { num = strspn(needle, accept); if (num) { ch = needle[num]; needle[num] = 0; if (inet_pton(AF_INET, needle, &addr) == 1) { inet_ntop(AF_INET, &addr, address, len); if (is_address_valid(AF_INET, address)) { found = 1; break; } } needle[num] = ch; } } /* nothing yet, skip to next search point */ haystack = needle + num + 1; } return found; } static int parse_ipv6_address(char *buffer, char *address, size_t len) { int found = 0; char *accept = "0123456789abcdefABCDEF:"; char *needle, *haystack, *end; struct in6_addr addr; haystack = buffer; needle = haystack; end = haystack + strlen(haystack) - 1; while (needle && haystack < end) { char ch; size_t num = 0; needle = strpbrk(haystack, accept); if (needle) { num = strspn(needle, accept); if (num) { ch = needle[num]; needle[num] = 0; if (inet_pton(AF_INET6, needle, &addr) == 1) { inet_ntop(AF_INET6, &addr, address, len); if (is_address_valid(AF_INET6, address)) { found = 1; break; } } needle[num] = ch; } } /* nothing yet, skip to next search point */ haystack = needle + num + 1; } return found; } static int parse_my_address(char *buffer, char *address, size_t len) { if (parse_ipv6_address(buffer, address, len)) return 0; return !parse_ipv4_address(buffer, address, len); } static int get_address_remote(ddns_t *ctx, ddns_info_t *info, char *address, size_t len) { if (!info->server_url[0]) return 1; DO(server_transaction(ctx, info)); if (!ctx || ctx->http_transaction.rsp_len <= 0 || !ctx->http_transaction.rsp) return RC_INVALID_POINTER; logit(LOG_DEBUG, "IP server response:"); logit(LOG_DEBUG, "%s", ctx->work_buf); DO(parse_my_address(ctx->http_transaction.rsp_body, address, len)); return 0; } static int get_address_cmd(ddns_t *ctx, ddns_info_t *info, char *address, size_t len) { if (!info->checkip_cmd || !info->checkip_cmd[0]) return 1; DO(shell_transaction(ctx, info, info->checkip_cmd)); logit(LOG_DEBUG, "Command response:"); logit(LOG_DEBUG, "%s", ctx->work_buf); DO(parse_my_address(ctx->work_buf, address, len)); return 0; } static int get_ipv4_address_iface(const char *ifname, char *address, size_t len) { int sd, result; struct ifreq ifr; sd = socket(PF_INET, SOCK_DGRAM, 0); if (sd < 0) { logit(LOG_WARNING, "Failed opening network socket: %s", strerror(errno)); return 1; } logit(LOG_DEBUG, "Reading IPv4 address of %s using SIOCGIFADDR ...", ifname); memset(&ifr, 0, sizeof(struct ifreq)); ifr.ifr_addr.sa_family = AF_INET; snprintf(ifr.ifr_name, IFNAMSIZ, "%s", ifname); result = ioctl(sd, SIOCGIFADDR, &ifr); close(sd); if (result < 0) { logit(LOG_ERR, "Failed reading IP address of interface %s: %s", ifname, strerror(errno)); return 1; } if (!inet_ntop(AF_INET, &((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr, address, len)) return 1; if (!is_address_valid(AF_INET, address)) { logit(LOG_INFO, "Interface %s has an invalid/local IP# %s", ifname, address); return 1; } return 0; } static int get_address_iface(ddns_t *ctx, const char *ifname, char *address, size_t len) { char *ptr, trailer[IFNAMSIZ + 2]; struct ifaddrs *ifaddr, *ifa; if (!ifname || !ifname[0]) return 1; /* Trailer to strip, if set by getnameinfo() */ snprintf(trailer, sizeof(trailer), "%%%s", ifname); logit(LOG_INFO, "Checking for IP# change, querying interface %s", ifname); if (getifaddrs(&ifaddr)) return get_ipv4_address_iface(ifname, address, len); memset(ctx->work_buf, 0, ctx->work_buflen); for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) { int result, family; char host[NI_MAXHOST] = ""; size_t pos; if (!ifa->ifa_addr) continue; if (!string_compare(ifa->ifa_name, ifname)) continue; pos = strlen(ctx->work_buf); family = ifa->ifa_addr->sa_family; if (family == AF_INET || family == AF_INET6) { result = getnameinfo(ifa->ifa_addr, ((family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); if (result) { logit(LOG_ERR, "getnameinfo() failed: %s", gai_strerror(result)); continue; } ptr = strstr(host, trailer); if (ptr) *ptr = 0; if (!is_address_valid(family, host)) { logit(LOG_INFO, "Invalid/local address %s for %s, skipping ...", host, ifname); continue; } snprintf(&ctx->work_buf[pos], ctx->work_buflen - pos, "%s\n", host); } } freeifaddrs(ifaddr); DO(parse_my_address(ctx->work_buf, address, len)); return 0; } static int get_address_backend(ddns_t *ctx, ddns_info_t *info, char *address, size_t len) { char name[sizeof(info->checkip_name.name)]; char url[sizeof(info->checkip_url)]; int rc; logit(LOG_DEBUG, "Get address for %s", info->system->name); memset(address, 0, len); if (!get_address_cmd (ctx, info, address, len)) return 0; if (!get_address_iface (ctx, iface,address, len)) return 0; if (!get_address_remote(ctx, info, address, len)) return 0; logit(LOG_WARNING, "Communication with checkip server %s failed, " "run again with 'inadyn -l debug' if problem persists", info->checkip_name.name); /* Skip fallback if it's the same server ... option: flip SSL bit? */ if (strstr(info->checkip_name.name, DDNS_MY_IP_SERVER)) goto error; logit(LOG_WARNING, "Retrying with built-in 'default', api.ipify.org ..."); /* keep backup, for now, future extension: count failures and replace permanently */ strlcpy(name, info->checkip_name.name, sizeof(name)); strlcpy(url, info->checkip_url, sizeof(url)); /* Retry with http(s)://api.ipify.org/ */ strlcpy(info->checkip_name.name, DDNS_MY_IP_SERVER, sizeof(info->checkip_name.name)); strlcpy(info->checkip_url, "/", sizeof(info->checkip_url)); rc = get_address_remote(ctx, info, address, len); /* restore backup, for now, the official server may just have temporary problems */ strlcpy(info->checkip_name.name, name, sizeof(info->checkip_name.name)); strlcpy(info->checkip_url, url, sizeof(info->checkip_url)); if (!rc) { logit(LOG_WARNING, "Please note, %s seems unstable, consider overriding it " "in your configuration with 'checkip-server = default'", info->checkip_name.name); return 0; } error: logit(LOG_ERR, "Failed to get IP address for %s, giving up!", info->system->name); return 1; } /* * Fetch IP, using any of the backends for each DDNS provider, * then check for address change. */ static int get_address(ddns_t *ctx) { char address[MAX_ADDRESS_LEN]; ddns_info_t *info; info = conf_info_iterator(1); while (info) { int anychange = 0; size_t i; if (get_address_backend(ctx, info, address, sizeof(address))) goto next; for (i = 0; i < info->alias_count; i++) { ddns_alias_t *alias = &info->alias[i]; alias->ip_has_changed = strncmp(alias->address, address, sizeof(alias->address)) != 0; if (alias->ip_has_changed) { anychange++; strlcpy(alias->address, address, sizeof(alias->address)); } #ifdef ENABLE_SIMULATION logit(LOG_WARNING, "In simulation, forcing IP# change ..."); alias->ip_has_changed = 1; #endif } if (!anychange) logit(LOG_INFO, "No IP# change detected for %s, still at %s", info->system->name, address); else logit(LOG_INFO, "Current IP# %s at %s", address, info->system->name); next: info = conf_info_iterator(0); } return 0; } static int time_to_check(ddns_t *ctx, ddns_alias_t *alias) { time_t past_time = time(NULL) - alias->last_update; return ctx->force_addr_update || (past_time > ctx->forced_update_period_sec); } static int check_alias_update_table(ddns_t *ctx) { ddns_info_t *info; /* Uses fix test if ip of server 0 has changed. * That should be OK even if changes check_address() to * iterate over servernum, but not if it's fix set to =! 0 */ info = conf_info_iterator(1); while (info) { size_t i; for (i = 0; i < info->alias_count; i++) { int override; ddns_alias_t *alias = &info->alias[i]; /* XXX: TODO time_to_check() will return false positive if the cache * file is missing => causing unnecessary update. We should save * the cache file with the current IP instead and fall back to * standard update interval! */ override = time_to_check(ctx, alias); if (!alias->ip_has_changed && !override) { alias->update_required = 0; continue; } alias->update_required = 1; logit(LOG_NOTICE, "Update %s for alias %s, new IP# %s", override ? "forced" : "needed", alias->name, alias->address); } info = conf_info_iterator(0); } return 0; } static int send_update(ddns_t *ctx, ddns_info_t *info, ddns_alias_t *alias, int *changed) { int rc; http_trans_t trans; http_t *client = &info->server; if (info->system->setup) DO(info->system->setup(ctx, info, alias)); client->ssl_enabled = info->ssl_enabled; rc = http_init(client, "Sending IP# update to DDNS server"); if (rc) { /* Update failed, force update again in ctx->cmd_check_period seconds */ ctx->force_addr_update = 1; return rc; } memset(ctx->work_buf, 0, ctx->work_buflen); memset(ctx->request_buf, 0, ctx->request_buflen); memset(&trans, 0, sizeof(trans)); trans.req_len = info->system->request(ctx, info, alias); trans.req = (char *)ctx->request_buf; trans.rsp = (char *)ctx->work_buf; trans.max_rsp_len = ctx->work_buflen - 1; /* Save place for a \0 at the end */ if (trans.req_len < 0) { logit(LOG_ERR, "Invalid HTTP GET request in %s provider, cannot update.", info->system->name); rc = RC_ERROR; goto exit; } #ifdef ENABLE_SIMULATION logit(LOG_WARNING, "In simulation, skipping update to server ..."); goto exit; #endif ctx->request_buf[trans.req_len] = 0; logit(LOG_DEBUG, "Sending alias table update to DDNS server: %s", ctx->request_buf); rc = http_transaction(client, &trans); if (rc) { /* Update failed, force update again in ctx->cmd_check_period seconds */ logit(LOG_WARNING, "HTTP(S) Transaction failed, error %d: %s", rc, error_str(rc)); logit(LOG_INFO, "Update failed, forced update/retry in %d sec ...", ctx->cmd_check_period); ctx->force_addr_update = 1; goto exit; } logit(LOG_DEBUG, "DDNS server response: %s", trans.rsp); rc = info->system->response(&trans, info, alias); if (rc) { logit(LOG_WARNING, "%s error in DDNS server response:", rc == RC_DDNS_RSP_RETRY_LATER ? "Temporary" : "Fatal"); logit(LOG_WARNING, "[%d %s] %s", trans.status, trans.status_desc, trans.rsp_body != trans.rsp ? trans.rsp_body : ""); /* Update failed, force update again in ctx->cmd_check_period seconds */ ctx->force_addr_update = 1; } else { logit(LOG_INFO, "Successful alias table update for %s => new IP# %s", alias->name, alias->address); ctx->force_addr_update = 0; if (changed) (*changed)++; } exit: http_exit(client); return rc; } static int update_alias_table(ddns_t *ctx) { int rc = 0, remember = 0; int anychange = 0; ddns_info_t *info; /* Issue #15: On external trig. force update to random addr. */ if (ctx->force_addr_update && ctx->forced_update_fake_addr) { /* If the DDNS server responds with an error, we ignore it here, * since this is just to fool the DDNS server to register a a * change, i.e., an active user. */ info = conf_info_iterator(1); while (info) { size_t i; for (i = 0; i < info->alias_count; i++) { ddns_alias_t *alias = &info->alias[i]; char backup[sizeof(alias->address)]; strlcpy(backup, alias->address, sizeof(backup)); /* Picking random address in 203.0.113.0/24 ... */ snprintf(alias->address, sizeof(alias->address), "203.0.113.%d", (rand() + 1) % 255); TRY(send_update(ctx, info, alias, NULL)); strlcpy(alias->address, backup, sizeof(alias->address)); } info = conf_info_iterator(0); } /* Play nice with server, wait a bit before sending actual IP */ sleep(3); } info = conf_info_iterator(1); while (info) { size_t i; for (i = 0; i < info->alias_count; i++) { ddns_alias_t *alias = &info->alias[i]; char *event = "update"; rc = 0; if (!alias->update_required) { if (exec_mode == EXEC_MODE_COMPAT) continue; event = "nochg"; } else if ((rc = send_update(ctx, info, alias, &anychange))) { if (exec_mode == EXEC_MODE_COMPAT) break; event = "error"; } else { /* Only reset if send_update() succeeds. */ alias->update_required = 0; alias->last_update = time(NULL); /* Update cache file for this entry */ write_cache_file(alias); } /* Run command or script on successful update. */ if (script_exec) os_shell_execute(script_exec, alias->address, alias->name, event, rc); } if (RC_DDNS_RSP_NOTOK == rc || RC_DDNS_RSP_AUTH_FAIL == rc) remember = rc; if (RC_DDNS_RSP_RETRY_LATER == rc && !remember) remember = rc; info = conf_info_iterator(0); } return remember; } static int get_encoded_user_passwd(void) { int rc = 0; char *buf = NULL; size_t len; ddns_info_t *info; /* Take base64 encoding into account when allocating buf */ len = sizeof(info->creds.password) + sizeof(info->creds.username) + 2; len = (len / 3 + ((len % 3) ? 1 : 0)) * 4; /* output length = 4 * [input len / 3] */ buf = calloc(len, sizeof(char)); if (!buf) return RC_OUT_OF_MEMORY; info = conf_info_iterator(1); while (info) { int rc2; char *encode; size_t dlen = 0; info->creds.encoded = 0; /* * Concatenate username and password with a ':', without * snprintf(), since that can cause information loss if * the password has "\=" or similar in it, issue #57 */ strlcpy(buf, info->creds.username, len); strlcat(buf, ":", len); strlcat(buf, info->creds.password, len); /* query required buffer size for base64 encoded data */ base64_encode(NULL, &dlen, (unsigned char *)buf, strlen(buf)); encode = malloc(dlen); if (!encode) { logit(LOG_WARNING, "Out of memory base64 encoding user:pass for %s!", info->system->name); rc = RC_OUT_OF_MEMORY; break; } // logit(LOG_DEBUG, "Base64 encode %s for %s ...", buf, info->system->name); rc2 = base64_encode((unsigned char *)encode, &dlen, (unsigned char *)buf, strlen(buf)); if (rc2) { logit(LOG_WARNING, "Failed base64 encoding user:pass for %s!", info->system->name); free(encode); rc = RC_BUFFER_OVERFLOW; break; } logit(LOG_DEBUG, "Base64 encoded string: %s", encode); info->creds.encoded_password = encode; info->creds.encoded = 1; info->creds.size = strlen(info->creds.encoded_password); info = conf_info_iterator(0); } memset(buf, 0, len); free(buf); return rc; } static int init_context(ddns_t *ctx) { ddns_info_t *info; struct timeval tv; if (!ctx) return RC_INVALID_POINTER; if (ctx->initialized == 1) return 0; /* Seed prng, used in silly IP randomizer */ gettimeofday(&tv, NULL); srand((unsigned int)tv.tv_usec); info = conf_info_iterator(1); while (info) { http_t *checkip = &info->checkip; http_t *update = &info->server; if (strlen(info->proxy_name.name)) { http_set_port(checkip, info->proxy_name.port); http_set_port(update, info->proxy_name.port); http_set_remote_name(checkip, info->proxy_name.name); http_set_remote_name(update, info->proxy_name.name); } else { http_set_port(checkip, info->checkip_name.port); http_set_port(update, info->server_name.port); http_set_remote_name(checkip, info->checkip_name.name); http_set_remote_name(update, info->server_name.name); } info = conf_info_iterator(0); } /* Restore values, if reset by SIGHUP. Initialize time from cache file at startup. */ ctx->num_iterations = cached_num_iterations; ctx->initialized = 1; return 0; } static int check_address(ddns_t *ctx) { if (!ctx) return RC_INVALID_POINTER; /* Get IP address from any of the different backends */ DO(get_address(ctx)); /* Step through aliases list, resolve them and check if they point to my IP */ DO(check_alias_update_table(ctx)); /* Update IPs marked as not identical with my IP */ DO(update_alias_table(ctx)); return 0; } /* * Error filter. Some errors are to be expected in a network * application, some we can recover from, wait a shorter while and try * again, whereas others are terminal, e.g., some OS errors. */ static int check_error(ddns_t *ctx, int rc) { const char *errstr = "Error response from DDNS server"; switch (rc) { case RC_OK: ctx->update_period = ctx->normal_update_period_sec; break; /* dyn_dns_update_ip() failed, inform the user the (network) error * is not fatal and that we will retry again in a short while. */ case RC_TCP_INVALID_REMOTE_ADDR: /* Probably temporary DNS error. */ case RC_TCP_CONNECT_FAILED: /* Cannot connect to DDNS server atm. */ case RC_TCP_SEND_ERROR: case RC_TCP_RECV_ERROR: case RC_OS_INVALID_IP_ADDRESS: case RC_DDNS_RSP_RETRY_LATER: case RC_DDNS_INVALID_CHECKIP_RSP: ctx->update_period = ctx->error_update_period_sec; logit(LOG_WARNING, "Will retry again in %d sec ...", ctx->update_period); break; case RC_DDNS_RSP_NOTOK: case RC_DDNS_RSP_AUTH_FAIL: if (ignore_errors) { logit(LOG_WARNING, "%s, ignoring ...", errstr); break; } logit(LOG_ERR, "%s, exiting!", errstr); return 1; /* All other errors, socket creation failures, invalid pointers etc. */ default: logit(LOG_ERR, "Unrecoverable error %d, exiting ...", rc); return 1; } return 0; } int ddns_main_loop(ddns_t *ctx) { int rc = 0; static int first_startup = 1; if (!ctx) return RC_INVALID_POINTER; /* On first startup only, optionally wait for network and any NTP daemon * to set system time correctly. Intended for devices without battery * backed real time clocks as initialization of time since last update * requires the correct time. Sleep can be interrupted with the usual * signals inadyn responds too. */ if (first_startup && startup_delay) { logit(LOG_NOTICE, "Startup delay: %d sec ...", startup_delay); first_startup = 0; /* Now sleep a while. Using the time set in update_period data member */ ctx->update_period = startup_delay; wait_for_cmd(ctx); if (ctx->cmd == CMD_STOP) { logit(LOG_NOTICE, "STOP command received, exiting."); return 0; } if (ctx->cmd == CMD_RESTART) { logit(LOG_INFO, "RESTART command received, restarting."); return RC_RESTART; } if (ctx->cmd == CMD_FORCED_UPDATE) { logit(LOG_INFO, "FORCED_UPDATE command received, updating now."); ctx->force_addr_update = 1; ctx->cmd = NO_CMD; } else if (ctx->cmd == CMD_CHECK_NOW) { logit(LOG_INFO, "CHECK_NOW command received, leaving startup delay."); ctx->cmd = NO_CMD; } } DO(init_context(ctx)); DO(read_cache_file(ctx)); DO(get_encoded_user_passwd()); if (once && force) ctx->force_addr_update = 1; /* Initialization done, create pidfile to indicate we are ready to communicate */ if (once == 0 && pidfile_name[0] && pidfile(pidfile_name)) logit(LOG_WARNING, "Failed creating pidfile: %s", strerror(errno)); /* DDNS client main loop */ while (1) { rc = check_address(ctx); if (RC_OK == rc) { if (ctx->total_iterations != 0 && ++ctx->num_iterations >= ctx->total_iterations) break; } if (ctx->cmd == CMD_RESTART) { logit(LOG_INFO, "RESTART command received. Restarting."); ctx->cmd = NO_CMD; rc = RC_RESTART; break; } /* On error, check why, possibly need to retry sooner ... */ if (check_error(ctx, rc)) break; /* Now sleep a while. Using the time set in update_period data member */ wait_for_cmd(ctx); if (ctx->cmd == CMD_STOP) { logit(LOG_NOTICE, "STOP command received, exiting."); rc = 0; break; } if (ctx->cmd == CMD_RESTART) { logit(LOG_INFO, "RESTART command received, restarting."); rc = RC_RESTART; break; } if (ctx->cmd == CMD_FORCED_UPDATE) { logit(LOG_INFO, "FORCED_UPDATE command received, updating now."); ctx->force_addr_update = 1; ctx->cmd = NO_CMD; continue; } if (ctx->cmd == CMD_CHECK_NOW) { logit(LOG_INFO, "CHECK_NOW command received, checking ..."); ctx->cmd = NO_CMD; continue; } } /* Save old value, if restarted by SIGHUP */ cached_num_iterations = ctx->num_iterations; return rc; } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/src/error.c000066400000000000000000000076161400562756000151070ustar00rootroot00000000000000/* Error code definitions * * Copyright (C) 2003-2004 Narcis Ilisei * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "../include/error.h" #include typedef struct { int rc; const char *p_name; } ERROR_NAME; static const ERROR_NAME global_error_table[] = { { RC_OK, "OK" }, { RC_ERROR, "Error" }, { RC_INVALID_POINTER, "Invalid pointer" }, { RC_OUT_OF_MEMORY, "Out of memory" }, { RC_BUFFER_OVERFLOW, "Too small internal buffer" }, { RC_PIDFILE_EXISTS_ALREADY, "Already running" }, { RC_TCP_SOCKET_CREATE_ERROR, "Failed creating IP socket" }, { RC_TCP_BAD_PARAMETER, "Invalid Internet port" }, { RC_TCP_INVALID_REMOTE_ADDR, "Temporary network error (DNS)" }, { RC_TCP_CONNECT_FAILED, "Failed connecting to DDNS server" }, { RC_TCP_SEND_ERROR, "Temporary network error (send)" }, { RC_TCP_RECV_ERROR, "Temporary network error (recv)" }, { RC_TCP_OBJECT_NOT_INITIALIZED, "Internal error (TCP)" }, { RC_HTTP_OBJECT_NOT_INITIALIZED, "Internal error (HTTP)" }, { RC_HTTPS_NO_TRUSTED_CA_STORE, "System has no trusted CA store" }, { RC_HTTPS_OUT_OF_MEMORY, "Out of memory (HTTPS)" }, { RC_HTTPS_FAILED_CONNECT, "Failed connecting to DDNS server (HTTPS)" }, { RC_HTTPS_FAILED_GETTING_CERT, "Failed retrieving DDNS server cert (HTTPS)" }, { RC_HTTPS_SEND_ERROR, "Temporary network error (HTTPS send)" }, { RC_HTTPS_RECV_ERROR, "Temporary network error (HTTPS recv)" }, { RC_HTTPS_SNI_ERROR, "Failed setting HTTPS server name" }, { RC_HTTPS_INVALID_REQUEST, "Invalid request (HTTPS)" }, { RC_DDNS_INVALID_CHECKIP_RSP, "Check IP server response not OK" }, { RC_DDNS_INVALID_OPTION, "Invalid or missing DDNS option" }, { RC_DDNS_RSP_NOTOK, "DDNS server response not OK" }, { RC_DDNS_RSP_RETRY_LATER, "DDNS server busy, try later" }, { RC_DDNS_RSP_AUTH_FAIL, "Authentication failure" }, { RC_OS_FORK_FAILURE, "Failed forking off child" }, { RC_OS_CHANGE_PERSONA_FAILURE, "Failed dropping privileges" }, { RC_OS_INVALID_UID, "Invalid or unknown UID" }, { RC_OS_INVALID_GID, "Invalid or unknown GID" }, { RC_FILE_IO_ACCESS_ERROR, "Failed create/modify file/dir" }, { RC_FILE_IO_MISSING_FILE, "Missing .conf file" }, { RC_OK, NULL } }; static const char *unknown_error = "Unknown error"; const char *error_str(int rc) { const ERROR_NAME *it = global_error_table; while (it->p_name) { if (it->rc == rc) return it->p_name; it++; } return unknown_error; } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/src/gnutls.c000066400000000000000000000214531400562756000152650ustar00rootroot00000000000000/* GnuTLS interface for optional HTTPS functions * * Copyright (C) 2014-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include "log.h" #include "http.h" #include "ssl.h" extern char *prognm; static gnutls_certificate_credentials_t xcred; /* This function will verify the peer's certificate, and check * if the hostname matches, as well as the activation, expiration dates. */ static int verify_certificate_callback(gnutls_session_t session) { unsigned int status; const gnutls_datum_t *cert_list; unsigned int cert_list_size; int ret; gnutls_x509_crt_t cert; const char *hostname; /* read hostname */ hostname = gnutls_session_get_ptr(session); /* This verification function uses the trusted CAs in the credentials * structure. So you must have installed one or more CA certificates. */ ret = gnutls_certificate_verify_peers2(session, &status); if (ret < 0) { logit(LOG_ERR, "Failed verifying certificate peers."); goto error; } if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) logit(LOG_WARNING, "The certificate does not have a known issuer."); if (status & GNUTLS_CERT_REVOKED) logit(LOG_WARNING, "The certificate has been revoked."); if (status & GNUTLS_CERT_EXPIRED) logit(LOG_WARNING, "The certificate has expired."); if (status & GNUTLS_CERT_NOT_ACTIVATED) { logit(LOG_WARNING, "The certificate is not yet activated."); if (broken_rtc && (status &= ~GNUTLS_CERT_NOT_ACTIVATED) == GNUTLS_CERT_INVALID) status = 0; } if (status & GNUTLS_CERT_INVALID) { logit(LOG_ERR, "The certificate is not trusted."); goto error; } /* Up to here the process is the same for X.509 certificates and * OpenPGP keys. From now on X.509 certificates are assumed. This can * be easily extended to work with openpgp keys as well. */ if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) { logit(LOG_ERR, "Not a valid X.509 certificate"); goto error; } if (gnutls_x509_crt_init(&cert) < 0) { logit(LOG_ERR, "Failed init of X.509 cert engine"); goto error; } cert_list = gnutls_certificate_get_peers(session, &cert_list_size); if (cert_list == NULL) { logit(LOG_ERR, "No certificate was found!"); goto error; } if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0) { logit(LOG_ERR, "Error while parsing certificate."); goto error; } if (!gnutls_x509_crt_check_hostname(cert, hostname)) { logit(LOG_ERR, "The certificate's owner does not match the hostname '%s'", hostname); goto error; } gnutls_x509_crt_deinit(cert); /* notify gnutls to continue handshake normally */ logit(LOG_DEBUG, "Certificate OK"); return 0; error: if (secure_ssl) return GNUTLS_E_CERTIFICATE_ERROR; return 0; } static int ssl_set_ca_location(void) { int num = 0; /* A user defined CA PEM bundle overrides any built-ins or fall-backs */ if (ca_trust_file) { num = gnutls_certificate_set_x509_trust_file(xcred, ca_trust_file, GNUTLS_X509_FMT_PEM); goto done; } #ifdef gnutls_certificate_set_x509_system_trust /* Since 3.0.20 */ num = gnutls_certificate_set_x509_system_trust(xcred); #endif if (num <= 0) num = gnutls_certificate_set_x509_trust_file(xcred, CAFILE1, GNUTLS_X509_FMT_PEM); if (num <= 0) num = gnutls_certificate_set_x509_trust_file(xcred, CAFILE2, GNUTLS_X509_FMT_PEM); done: if (num <= 0) return 1; return 0; } int ssl_init(void) { if (!gnutls_check_version("3.1.4")) { logit(LOG_ERR, "%s requires GnuTLS 3.1.4 or later for SSL", prognm); exit(1); } /* for backwards compatibility with gnutls < 3.3.0 */ gnutls_global_init(); /* X509 stuff */ gnutls_certificate_allocate_credentials(&xcred); /* Try to figure out location of trusted CA certs on system */ if (ssl_set_ca_location()) return RC_HTTPS_NO_TRUSTED_CA_STORE; gnutls_certificate_set_verify_function(xcred, verify_certificate_callback); return 0; } void ssl_exit(void) { gnutls_certificate_free_credentials(xcred); gnutls_global_deinit(); } void ssl_get_info(http_t *client) { #ifndef gnutls_session_get_desc (void)client; #else char *info; /* Available since 3.1.10 */ info = gnutls_session_get_desc(client->ssl); logit(LOG_INFO, "SSL connection using: %s", info); gnutls_free(info); #endif } int ssl_open(http_t *client, char *msg) { int ret; char buf[256]; size_t len; const char *sn, *err; const gnutls_datum_t *cert_list; unsigned int cert_list_size = 0; gnutls_x509_crt_t cert; if (!client->ssl_enabled) return tcp_init(&client->tcp, msg); /* Initialize TLS session */ logit(LOG_INFO, "%s, initiating HTTPS ...", msg); gnutls_init(&client->ssl, GNUTLS_CLIENT); /* SSL SNI support: tell the servername we want to speak to */ http_get_remote_name(client, &sn); gnutls_session_set_ptr(client->ssl, (void *)sn); if (gnutls_server_name_set(client->ssl, GNUTLS_NAME_DNS, sn, strlen(sn))) return RC_HTTPS_SNI_ERROR; /* Use default priorities */ ret = gnutls_priority_set_direct(client->ssl, "NORMAL", &err); if (ret < 0) { if (ret == GNUTLS_E_INVALID_REQUEST) logit(LOG_ERR, "Syntax error at: %s", err); return RC_HTTPS_INVALID_REQUEST; } /* put the x509 credentials to the current session */ gnutls_credentials_set(client->ssl, GNUTLS_CRD_CERTIFICATE, xcred); /* connect to the peer */ tcp_set_port(&client->tcp, HTTPS_DEFAULT_PORT); DO(tcp_init(&client->tcp, msg)); /* Forward TCP socket to GnuTLS, the set_int() API is perhaps too new still ... since 3.1.9 */ // gnutls_transport_set_int(client->ssl, client->tcp.socket); gnutls_transport_set_ptr(client->ssl, (gnutls_transport_ptr_t)(intptr_t)client->tcp.socket); /* Perform the TLS handshake, ignore non-fatal errors. */ do { ret = gnutls_handshake(client->ssl); } while (ret != 0 && !gnutls_error_is_fatal(ret)); if (gnutls_error_is_fatal(ret)) { logit(LOG_ERR, "SSL handshake with %s failed: %s", sn, gnutls_strerror(ret)); return RC_HTTPS_FAILED_CONNECT; } ssl_get_info(client); /* Get server's certificate (note: beware of dynamic allocation) - opt */ cert_list = gnutls_certificate_get_peers(client->ssl, &cert_list_size); if (cert_list_size > 0) { if (gnutls_x509_crt_init(&cert)) return RC_HTTPS_FAILED_GETTING_CERT; gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER); len = sizeof(buf); gnutls_x509_crt_get_dn(cert, buf, &len); logit(LOG_INFO, "SSL server cert subject: %s", buf); len = sizeof(buf); gnutls_x509_crt_get_issuer_dn(cert, buf, &len); logit(LOG_INFO, "SSL server cert issuer: %s", buf); gnutls_x509_crt_deinit(cert); } return 0; } int ssl_close(http_t *client) { if (client->ssl_enabled) { gnutls_bye(client->ssl, GNUTLS_SHUT_WR); gnutls_deinit(client->ssl); } return tcp_exit(&client->tcp); } int ssl_send(http_t *client, const char *buf, int len) { int ret; if (!client->ssl_enabled) return tcp_send(&client->tcp, buf, len); do { ret = gnutls_record_send(client->ssl, buf, len); } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); if (ret < 0) return RC_HTTPS_SEND_ERROR; logit(LOG_DEBUG, "Successfully sent HTTPS request!"); return 0; } int ssl_recv(http_t *client, char *buf, int buf_len, int *recv_len) { int ret, len = 0; if (!client->ssl_enabled) return tcp_recv(&client->tcp, buf, buf_len, recv_len); do { ret = gnutls_record_recv(client->ssl, buf + len, buf_len - len); if (ret > 0) { len += ret; } } while (ret > 0 || ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); /* * We may get GNUTLS_E_PREMATURE_TERMINATION here. It happens * when a server closes the TCP connection without a prior TLS * shutdown alert. Probably indicates a bug in the server's * TLS handling. OpenSSL seems to ignore this so we do too. * -- André Colomb */ if (ret < 0 && ret != GNUTLS_E_PREMATURE_TERMINATION) { logit(LOG_WARNING, "Failed receiving HTTPS response: %s", gnutls_strerror(ret)); return RC_HTTPS_RECV_ERROR; } *recv_len = len; logit(LOG_DEBUG, "Successfully received HTTPS response (%d/%d bytes)!", *recv_len, buf_len); return 0; } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/src/http.c000066400000000000000000000102671400562756000147310ustar00rootroot00000000000000/* Interface for HTTP functions * * Copyright (C) 2003-2004 Narcis Ilisei * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include "ssl.h" #include "http.h" #include "error.h" int http_construct(http_t *client) { ASSERT(client); DO(tcp_construct(&client->tcp)); memset((char *)client + sizeof(client->tcp), 0, sizeof(*client) - sizeof(client->tcp)); client->initialized = 0; return 0; } int http_destruct(http_t *client, int num) { int i = 0, rv = 0; while (i < num) rv = tcp_destruct(&client[i++].tcp); return rv; } static int local_set_params(http_t *client) { int timeout = 0; int port = 0; http_get_remote_timeout(client, &timeout); if (timeout == 0) http_set_remote_timeout(client, HTTP_DEFAULT_TIMEOUT); http_get_port(client, &port); if (port == 0) http_set_port(client, HTTP_DEFAULT_PORT); return 0; } int http_init(http_t *client, char *msg) { int rc = 0; do { TRY(local_set_params(client)); TRY(ssl_open(client, msg)); } while (0); if (rc) { http_exit(client); return rc; } client->initialized = 1; return 0; } int http_exit(http_t *client) { ASSERT(client); if (!client->initialized) return 0; client->initialized = 0; return ssl_close(client); } static void http_response_parse(http_trans_t *trans) { char *body; char *rsp = trans->rsp_body = trans->rsp; int status = trans->status = 0; const char sep[] = "\r\n\r\n"; memset(trans->status_desc, 0, sizeof(trans->status_desc)); if (rsp != NULL && (body = strstr(rsp, sep)) != NULL) { body += strlen(sep); trans->rsp_body = body; } /* * %*c : HTTP/1.0, 1.1 etc, discard read value * %4d : HTTP status code, e.g. 200 * %255[^\r\n] : HTTP status text, e.g. OK -- Reads max 255 bytes, including \0, not \r or \n */ if (sscanf(trans->rsp, "HTTP/1.%*c %4d %255[^\r\n]", &status, trans->status_desc) == 2) trans->status = status; } int http_transaction(http_t *client, http_trans_t *trans) { int rc = 0; ASSERT(client); ASSERT(trans); if (!client->initialized) return RC_HTTP_OBJECT_NOT_INITIALIZED; trans->rsp_len = 0; do { TRY(ssl_send(client, trans->req, trans->req_len)); TRY(ssl_recv(client, trans->rsp, trans->max_rsp_len, &trans->rsp_len)); } while (0); trans->rsp[trans->rsp_len] = 0; http_response_parse(trans); return rc; } int http_status_valid(int status) { if (status == 200) return 0; if (status == 401 || status == 403) return RC_DDNS_RSP_AUTH_FAIL; if (status >= 500 && status < 600) return RC_DDNS_RSP_RETRY_LATER; return RC_DDNS_RSP_NOTOK; } int http_set_port(http_t *client, int port) { ASSERT(client); return tcp_set_port(&client->tcp, port); } int http_get_port(http_t *client, int *port) { ASSERT(client); return tcp_get_port(&client->tcp, port); } int http_set_remote_name(http_t *client, const char *name) { ASSERT(client); return tcp_set_remote_name(&client->tcp, name); } int http_get_remote_name(http_t *client, const char **name) { ASSERT(client); return tcp_get_remote_name(&client->tcp, name); } int http_set_remote_timeout(http_t *client, int timeout) { ASSERT(client); return tcp_set_remote_timeout(&client->tcp, timeout); } int http_get_remote_timeout(http_t *client, int *timeout) { ASSERT(client); return tcp_get_remote_timeout(&client->tcp, timeout); } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/src/jsmn.c000066400000000000000000000024221400562756000147130ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2010 Serge Zaitsev * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /* The implementation is included here; JSMN_HEADER should be defined * for other includes. (Or just include json.h) */ #define JSMN_STRICT #include "jsmn.h" inadyn-2.8.1/src/json.c000066400000000000000000000037111400562756000147170ustar00rootroot00000000000000/* JSON helpers * * Copyright (C) 2019-2020 Simon Pilkington * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include "log.h" #include "json.h" int parse_json(const char *json, jsmntok_t *out_tokens[]) { int num_tokens; jsmn_parser parser; jsmn_init(&parser); num_tokens = jsmn_parse(&parser, json, strlen(json), NULL, 0); if (num_tokens < 0) { logit(LOG_ERR, "Failed to parse JSON."); return -1; } if (num_tokens == 0) { logit(LOG_WARNING, "No JSON found in string."); return -1; } *out_tokens = malloc(num_tokens * sizeof(jsmntok_t)); if (!(*out_tokens)) { logit(LOG_ERR, "Couldn't allocate memory to parse JSON."); return -1; } jsmn_init(&parser); jsmn_parse(&parser, json, strlen(json), *out_tokens, num_tokens); return num_tokens; } int jsoneq(const char *json, const jsmntok_t *tok, const char *s) { if (tok->type == JSMN_STRING && (int)strlen(s) == tok->end - tok->start && strncmp(json + tok->start, s, tok->end - tok->start) == 0) { return 0; } return -1; } int json_bool(const char *json, const jsmntok_t *token, int *out_value) { if (token->type == JSMN_PRIMITIVE) { *out_value = json[token->start] == 't'; return 0; } return -1; } inadyn-2.8.1/src/log.c000066400000000000000000000041131400562756000145240ustar00rootroot00000000000000/* Custom error logging system * * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #define SYSLOG_NAMES /* Expose syslog.h:prioritynames[] */ #include #include "compat.h" static int level = LOG_NOTICE; static int enabled = 0; void log_init(char *ident, int log, int bg) { int log_opts = LOG_PID | LOG_NDELAY; #ifdef LOG_PERROR if (!bg && log < 1) log_opts |= LOG_PERROR; #endif openlog(ident, log_opts, LOG_USER); setlogmask(LOG_UPTO(level)); enabled = 1; } void log_exit(void) { if (enabled) closelog(); } int log_level(char *arg) { int i, rc; for (i = 0; prioritynames[i].c_name; i++) { if (string_match(prioritynames[i].c_name, arg)) { level = prioritynames[i].c_val; return 0; } } rc = atoi(arg); if (-1 == rc) return rc; level = rc; return 0; } void vlogit(int prio, const char *fmt, va_list args) { if (enabled && level != INTERNAL_NOPRI) vsyslog(prio, fmt, args); else if (prio <= level) vfprintf(stderr, fmt, args), fprintf(stderr, "\n"); } void logit(int prio, const char *fmt, ...) { va_list args; va_start(args, fmt); vlogit(prio, fmt, args); va_end(args); } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/src/main.c000066400000000000000000000324511400562756000146750ustar00rootroot00000000000000/* Inadyn is a small and simple dynamic DNS (DDNS) client * * Copyright (C) 2003-2004 Narcis Ilisei * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include /* getpwnam() */ #include /* getgrnam() */ #include #include #include /* mkdir() */ #include "log.h" #include "ddns.h" #include "error.h" #include "ssl.h" int once = 0; int force = 0; /* Only allowed with 'once' */ int ignore_errors = 0; int startup_delay = DDNS_DEFAULT_STARTUP_SLEEP; int allow_ipv6 = 0; int secure_ssl = 1; /* Strict cert validation by default */ int broken_rtc = 0; /* Validate certificate time by default */ char *ca_trust_file = NULL; /* Custom CA trust file/bundle PEM format */ int verify_addr = 1; char *prognm = NULL; char *ident = PACKAGE_NAME; char *iface = NULL; char *use_iface = NULL; char *user_agent = DDNS_USER_AGENT; char *config = NULL; char *cache_dir = NULL; char *script_cmd = NULL; char *script_exec = NULL; int exec_mode = EXEC_MODE_COMPAT; char *pidfile_name = NULL; uid_t uid = 0; gid_t gid = 0; cfg_t *cfg; extern cfg_t *conf_parse_file (char *file, ddns_t *ctx); extern void conf_info_cleanup (void); static int alloc_context(ddns_t **pctx) { int rc = 0; ddns_t *ctx; if (!pctx) return RC_INVALID_POINTER; *pctx = (ddns_t *)malloc(sizeof(ddns_t)); if (!*pctx) return RC_OUT_OF_MEMORY; do { ctx = *pctx; memset(ctx, 0, sizeof(ddns_t)); /* Alloc space for http_to_ip_server data */ ctx->work_buflen = DDNS_HTTP_RESPONSE_BUFFER_SIZE; ctx->work_buf = (char *)malloc(ctx->work_buflen); if (!ctx->work_buf) { rc = RC_OUT_OF_MEMORY; break; } /* Alloc space for request data */ ctx->request_buflen = DDNS_HTTP_REQUEST_BUFFER_SIZE; ctx->request_buf = (char *)malloc(ctx->request_buflen); if (!ctx->request_buf) { rc = RC_OUT_OF_MEMORY; break; } ctx->cmd = NO_CMD; ctx->normal_update_period_sec = DDNS_DEFAULT_PERIOD; ctx->update_period = DDNS_DEFAULT_PERIOD; ctx->total_iterations = DDNS_DEFAULT_ITERATIONS; ctx->cmd_check_period = DDNS_DEFAULT_CMD_CHECK_PERIOD; ctx->force_addr_update = 0; ctx->initialized = 0; } while (0); if (rc) { if (ctx->work_buf) free(ctx->work_buf); if (ctx->request_buf) free(ctx->request_buf); free(ctx); *pctx = NULL; } return 0; } static void free_context(ddns_t *ctx) { if (!ctx) return; if (ctx->work_buf) { free(ctx->work_buf); ctx->work_buf = NULL; } if (ctx->request_buf) { free(ctx->request_buf); ctx->request_buf = NULL; } conf_info_cleanup(); free(ctx); } /* XXX: Should be called from forked child ... */ static int drop_privs(void) { if (uid) { if (gid != getgid()) { if (setgid(gid)) return 2; } if (uid != getuid()) { if (setuid(uid)) return 1; } } return 0; } static void parse_privs(char *user) { struct passwd *pw; char *group; if (!user) { pw = getpwuid(geteuid()); if (!pw) user = getenv("LOGNAME"); else user = pw->pw_name; } if (!user) { logit(LOG_INFO, "Cannot figure out username"); return; } group = strstr(user, ":"); if (group) *group++ = 0; pw = getpwnam(user); if (pw) { uid = pw->pw_uid; gid = pw->pw_gid; } if (group) { struct group *gr = getgrnam(group); if (gr) gid = gr->gr_gid; } } static int compose_paths(void) { /* Default .conf file path: "/etc" + '/' + "inadyn" + ".conf" */ if (!config) { size_t len = strlen(SYSCONFDIR) + strlen(ident) + 7; config = malloc(len); if (!config) { logit(LOG_ERR, "Failed allocating memory, exiting."); return RC_OUT_OF_MEMORY; } snprintf(config, len, "%s/%s.conf", SYSCONFDIR, ident); } /* Default is to let pidfile() API construct PID file from ident */ if (!pidfile_name) pidfile_name = strdup(ident); /* Default cache dir: "/var" + "/cache/" + "inadyn" */ if (!cache_dir) { size_t len = strlen(LOCALSTATEDIR) + strlen(ident) + 8; cache_dir = malloc(len); if (!cache_dir) { nomem: logit(LOG_ERR, "Failed allocating memory, exiting."); return RC_OUT_OF_MEMORY; } snprintf(cache_dir, len, "%s/cache/%s", LOCALSTATEDIR, ident); if (access(cache_dir, W_OK)) { char *home, *tmp; home = getenv("HOME"); if (!home) { logit(LOG_ERR, "Cannot create fallback cache dir: %s", strerror(errno)); return 0; } /* Fallback cache dir: $HOME + "/.cache/" + "inadyn" */ len = strlen(home) + strlen(ident) + 10; tmp = realloc(cache_dir, len); if (!tmp){ free(cache_dir); goto nomem; } else { cache_dir = tmp; } snprintf(cache_dir, len, "%s/.cache/%s", home, ident); if (mkdir(cache_dir, 0755) && EEXIST != errno) { snprintf(cache_dir, len, "%s/.%s", home, ident); mkdir(cache_dir, 0755); } } } return 0; } static int usage(int code) { char pidfn[80]; DO(compose_paths()); if (pidfile_name[0] != '/') snprintf(pidfn, sizeof(pidfn), "%s/%s.pid", RUNSTATEDIR, pidfile_name); else snprintf(pidfn, sizeof(pidfn), "%s", pidfile_name); fprintf(stderr, "Usage:\n %s [1hnsv] [-c CMD] [-e CMD] [-f FILE] [-l LVL] [-p USR:GRP] [-t SEC]\n\n" " -1, --once Run only once, updates if too old or unknown\n" " --force Force update, even if address has not changed\n" " --cache-dir=PATH Persistent cache dir of IP sent to providers.\n" " Default use ident NAME: %s/\n" " -c, --cmd=/path/to/cmd Script or command to run to check IP\n" " -C, --continue-on-error Ignore errors from DDNS provider\n" " -e, --exec=/path/to/cmd Script to run on DDNS update\n" " --exec-mode=MODE Set script run mode: compat, event:\n" " - compat: successful DDNS update only, default\n" " - event: any update status\n" " --check-config Verify syntax of configuration file and exit\n" " -f, --config=FILE Use FILE name for configuration, default uses\n" " ident NAME: %s\n" " -h, --help Show summary of command line options and exit\n" " -i, --iface=IFNAME Check IP of IFNAME instead of external server\n" " -I, --ident=NAME Identity for config file, PID file, cache dir,\n" " and syslog messages. Defaults to: %s\n" " -l, --loglevel=LEVEL Set log level: none, err, info, notice*, debug\n" " -n, --foreground Run in foreground with logging to stdout/stderr\n" " -p, --drop-privs=USER[:GROUP] Drop privileges after start to USER:GROUP\n" " --no-pidfile Do not create PID file, for use with systemd\n" " -P, --pidfile=FILE File to store process ID for signaling %s\n" " Default uses ident NAME: %s\n" " -s, --syslog Log to syslog, default unless --foreground\n" " -t, --startup-delay=SEC Initial startup delay, default none\n" " -v, --version Show program version and exit\n\n" "Bug report address: %s\n", prognm, cache_dir, config, prognm, prognm, pidfn, PACKAGE_BUGREPORT); #ifdef PACKAGE_URL fprintf(stderr, "Project homepage: %s\n", PACKAGE_URL); #endif return code; } static char *progname(char *arg0) { char *nm; nm = strrchr(arg0, '/'); if (nm) nm++; else nm = arg0; return nm; } int main(int argc, char *argv[]) { int c, restart, rc = 0; int use_syslog = 1; int check_config = 0; int background = 1; struct option opt[] = { { "once", 0, 0, '1' }, { "force", 0, 0, '4' }, { "cache-dir", 1, 0, 128 }, { "cmd", 1, 0, 'c' }, { "continue-on-error", 0, 0, 'C' }, { "exec", 1, 0, 'e' }, { "exec-mode", 1, 0, 130 }, { "config", 1, 0, 'f' }, { "check-config", 0, 0, 129 }, { "iface", 1, 0, 'i' }, { "ident", 1, 0, 'I' }, { "loglevel", 1, 0, 'l' }, { "help", 0, 0, 'h' }, { "foreground", 0, 0, 'n' }, { "no-pidfile", 0, 0, 'N' }, { "pidfile", 1, 0, 'P' }, { "drop-privs", 1, 0, 'p' }, { "syslog", 0, 0, 's' }, { "startup-delay", 1, 0, 't' }, { "version", 0, 0, 'v' }, { NULL, 0, 0, 0 } }; ddns_t *ctx = NULL; /* Set up initial values for uid + gid */ parse_privs(NULL); prognm = ident = progname(argv[0]); while ((c = getopt_long(argc, argv, "1c:Ce:f:h?i:I:l:nNp:P:st:v", opt, NULL)) != EOF) { switch (c) { case '1': /* --once */ once = 1; break; case '4': /* -- force */ force = 1; break; case 128: /* --cache-dir=PATH */ cache_dir = strdup(optarg); break; case 'c': /* --cmd=CMD */ script_cmd = optarg; break; case 'C': /* --continue-on-error */ ignore_errors = 1; break; case 'e': /* --exec=CMD */ script_exec = optarg; break; case 130: /* --exec-mode=MODE */ if (!strcmp(optarg, "event")) exec_mode = EXEC_MODE_EVENT; else if (!strcmp(optarg, "compat")) exec_mode = EXEC_MODE_COMPAT; else return usage(1); break; case 'f': /* --config=FILE */ config = strdup(optarg); break; case 129: /* --check-config */ check_config = 1; background = 0; use_syslog--; break; case 'i': /* --iface=IFNAME */ use_iface = iface = optarg; break; case 'I': /* --ident=NAME */ ident = optarg; break; case 'l': /* --loglevel=LEVEL */ rc = log_level(optarg); if (-1 == rc) return usage(1); break; case 'n': /* --foreground */ background = 0; use_syslog--; break; case 'N': /* --no-pidfile */ optarg = ""; /* fallthrough */ case 'P': /* --pidfile=NAME */ if (pidfile_name) free(pidfile_name); pidfile_name = strdup(optarg); break; case 'p': /* --drop-privs=USER[:GROUP] */ parse_privs(optarg); break; case 's': /* --syslog */ use_syslog++; break; case 't': /* --startup-delay=SEC */ startup_delay = atoi(optarg); break; case 'v': puts(VERSION); return 0; case 'h': /* --help */ case ':': /* Missing parameter for option. */ case '?': /* Unknown option. */ default: return usage(0); } } /* Figure out .conf file, cache directory, and PID file name */ DO(compose_paths()); if (check_config) { char pidfn[80]; if (pidfile_name[0] == 0) strlcpy(pidfn, "", sizeof(pidfn)); else if (pidfile_name[0] != '/') snprintf(pidfn, sizeof(pidfn), "%s/%s.pid", RUNSTATEDIR, pidfile_name); else snprintf(pidfn, sizeof(pidfn), "%s", pidfile_name); logit(LOG_DEBUG, "config : %s", config); logit(LOG_DEBUG, "pidfile : %s", pidfn); logit(LOG_DEBUG, "cache-dir : %s", cache_dir); rc = alloc_context(&ctx); if (rc) { logit(LOG_ERR, "Failed allocating memory, cannot check configuration file."); return rc; } logit(LOG_DEBUG, "Checking configuration file %s", config); cfg = conf_parse_file(config, ctx); if (!cfg) { free_context(ctx); return RC_ERROR; } logit(LOG_DEBUG, "Configuration file OK"); free_context(ctx); cfg_free(cfg); return RC_OK; } if (background) { if (daemon(0, 0) < 0) { logit(LOG_ERR, "Failed daemonizing %s: %s", ident, strerror(errno)); return RC_OS_FORK_FAILURE; } } /* Enable syslog or console debugging */ log_init(ident, use_syslog < 1 ? 0 : 1, background); /* Check permission to write PID and cache files */ if (!once) { DO(os_check_perms()); /* Only allowed with --once */ force = 0; } if (drop_privs()) { logit(LOG_WARNING, "Failed dropping privileges: %s", strerror(errno)); rc = RC_OS_CHANGE_PERSONA_FAILURE; goto leave; } /* "Hello!" Let user know we've started up OK */ logit(LOG_NOTICE, "%s", VERSION_STRING); /* Prepare SSL library, if enabled */ rc = ssl_init(); if (rc) goto leave; do { restart = 0; rc = alloc_context(&ctx); if (rc != RC_OK) break; rc = os_install_signal_handler(ctx); if (rc) { free_context(ctx); break; } cfg = conf_parse_file(config, ctx); if (!cfg) { rc = RC_FILE_IO_MISSING_FILE; free_context(ctx); break; } rc = ddns_main_loop(ctx); if (rc == RC_RESTART) restart = 1; free_context(ctx); cfg_free(cfg); } while (restart); ssl_exit(); leave: log_exit(); free(config); free(pidfile_name); free(cache_dir); if (rc) logit(LOG_ERR, "Error code %d: %s", rc, error_str(rc)); return rc; } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/src/makepath.c000066400000000000000000000035741400562756000155470ustar00rootroot00000000000000/* mkpath() -- Create all components leading up to a given directory * * Copyright (c) 2013-2020 Joachim Nilsson * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include "compat.h" /** * mkpath - Like makepath() but takes a mode_t argument * @dir: Directory to created, relative or absolute * @mode: A &mode_t mode to create @dir with * * Returns: * POSIX OK(0) on success, otherwise -1 with @errno set. */ int mkpath(char *dir, mode_t mode) { struct stat sb; if (!dir) { errno = EINVAL; return 1; } if (!stat(dir, &sb)) return 0; mkpath(dirname(strdupa(dir)), mode); return mkdir(dir, mode); } /** * makepath - Create all components of the specified directory. * @dir: Directory to create. * * Returns: * POSIX OK (0) on success, otherwise -1 and errno set appropriately. * This function returns EINVAL on bad argument, or ENOMEM when it * fails allocating temporary memory. For other error codes see the * mkdir() syscall description. */ int makepath(char *dir) { return mkpath(dir, 0777); } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/src/md5.c000066400000000000000000000200101400562756000144220ustar00rootroot00000000000000/* * RFC 1321 compliant MD5 implementation * * Copyright (C) 2006-2013, Brainspark B.V. * * This file is part of PolarSSL (http://www.polarssl.org) * Lead Maintainer: Paul Bakker * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* * The MD5 algorithm was designed by Ron Rivest in 1991. * * http://www.ietf.org/rfc/rfc1321.txt */ #include "md5.h" /* * 32-bit integer manipulation macros (little endian) */ #ifndef GET_UINT32_LE #define GET_UINT32_LE(n,b,i) \ { \ (n) = ( (uint32_t) (b)[(i) ] ) \ | ( (uint32_t) (b)[(i) + 1] << 8 ) \ | ( (uint32_t) (b)[(i) + 2] << 16 ) \ | ( (uint32_t) (b)[(i) + 3] << 24 ); \ } #endif #ifndef PUT_UINT32_LE #define PUT_UINT32_LE(n,b,i) \ { \ (b)[(i) ] = (unsigned char) ( (n) ); \ (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ } #endif /* * MD5 context setup */ void md5_starts( md5_context *ctx ) { ctx->total[0] = 0; ctx->total[1] = 0; ctx->state[0] = 0x67452301; ctx->state[1] = 0xEFCDAB89; ctx->state[2] = 0x98BADCFE; ctx->state[3] = 0x10325476; } static void md5_process( md5_context *ctx, const unsigned char data[64] ) { uint32_t X[16], A, B, C, D; GET_UINT32_LE( X[ 0], data, 0 ); GET_UINT32_LE( X[ 1], data, 4 ); GET_UINT32_LE( X[ 2], data, 8 ); GET_UINT32_LE( X[ 3], data, 12 ); GET_UINT32_LE( X[ 4], data, 16 ); GET_UINT32_LE( X[ 5], data, 20 ); GET_UINT32_LE( X[ 6], data, 24 ); GET_UINT32_LE( X[ 7], data, 28 ); GET_UINT32_LE( X[ 8], data, 32 ); GET_UINT32_LE( X[ 9], data, 36 ); GET_UINT32_LE( X[10], data, 40 ); GET_UINT32_LE( X[11], data, 44 ); GET_UINT32_LE( X[12], data, 48 ); GET_UINT32_LE( X[13], data, 52 ); GET_UINT32_LE( X[14], data, 56 ); GET_UINT32_LE( X[15], data, 60 ); #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) #define P(a,b,c,d,k,s,t) \ { \ a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \ } A = ctx->state[0]; B = ctx->state[1]; C = ctx->state[2]; D = ctx->state[3]; #define F(x,y,z) (z ^ (x & (y ^ z))) P( A, B, C, D, 0, 7, 0xD76AA478 ); P( D, A, B, C, 1, 12, 0xE8C7B756 ); P( C, D, A, B, 2, 17, 0x242070DB ); P( B, C, D, A, 3, 22, 0xC1BDCEEE ); P( A, B, C, D, 4, 7, 0xF57C0FAF ); P( D, A, B, C, 5, 12, 0x4787C62A ); P( C, D, A, B, 6, 17, 0xA8304613 ); P( B, C, D, A, 7, 22, 0xFD469501 ); P( A, B, C, D, 8, 7, 0x698098D8 ); P( D, A, B, C, 9, 12, 0x8B44F7AF ); P( C, D, A, B, 10, 17, 0xFFFF5BB1 ); P( B, C, D, A, 11, 22, 0x895CD7BE ); P( A, B, C, D, 12, 7, 0x6B901122 ); P( D, A, B, C, 13, 12, 0xFD987193 ); P( C, D, A, B, 14, 17, 0xA679438E ); P( B, C, D, A, 15, 22, 0x49B40821 ); #undef F #define F(x,y,z) (y ^ (z & (x ^ y))) P( A, B, C, D, 1, 5, 0xF61E2562 ); P( D, A, B, C, 6, 9, 0xC040B340 ); P( C, D, A, B, 11, 14, 0x265E5A51 ); P( B, C, D, A, 0, 20, 0xE9B6C7AA ); P( A, B, C, D, 5, 5, 0xD62F105D ); P( D, A, B, C, 10, 9, 0x02441453 ); P( C, D, A, B, 15, 14, 0xD8A1E681 ); P( B, C, D, A, 4, 20, 0xE7D3FBC8 ); P( A, B, C, D, 9, 5, 0x21E1CDE6 ); P( D, A, B, C, 14, 9, 0xC33707D6 ); P( C, D, A, B, 3, 14, 0xF4D50D87 ); P( B, C, D, A, 8, 20, 0x455A14ED ); P( A, B, C, D, 13, 5, 0xA9E3E905 ); P( D, A, B, C, 2, 9, 0xFCEFA3F8 ); P( C, D, A, B, 7, 14, 0x676F02D9 ); P( B, C, D, A, 12, 20, 0x8D2A4C8A ); #undef F #define F(x,y,z) (x ^ y ^ z) P( A, B, C, D, 5, 4, 0xFFFA3942 ); P( D, A, B, C, 8, 11, 0x8771F681 ); P( C, D, A, B, 11, 16, 0x6D9D6122 ); P( B, C, D, A, 14, 23, 0xFDE5380C ); P( A, B, C, D, 1, 4, 0xA4BEEA44 ); P( D, A, B, C, 4, 11, 0x4BDECFA9 ); P( C, D, A, B, 7, 16, 0xF6BB4B60 ); P( B, C, D, A, 10, 23, 0xBEBFBC70 ); P( A, B, C, D, 13, 4, 0x289B7EC6 ); P( D, A, B, C, 0, 11, 0xEAA127FA ); P( C, D, A, B, 3, 16, 0xD4EF3085 ); P( B, C, D, A, 6, 23, 0x04881D05 ); P( A, B, C, D, 9, 4, 0xD9D4D039 ); P( D, A, B, C, 12, 11, 0xE6DB99E5 ); P( C, D, A, B, 15, 16, 0x1FA27CF8 ); P( B, C, D, A, 2, 23, 0xC4AC5665 ); #undef F #define F(x,y,z) (y ^ (x | ~z)) P( A, B, C, D, 0, 6, 0xF4292244 ); P( D, A, B, C, 7, 10, 0x432AFF97 ); P( C, D, A, B, 14, 15, 0xAB9423A7 ); P( B, C, D, A, 5, 21, 0xFC93A039 ); P( A, B, C, D, 12, 6, 0x655B59C3 ); P( D, A, B, C, 3, 10, 0x8F0CCC92 ); P( C, D, A, B, 10, 15, 0xFFEFF47D ); P( B, C, D, A, 1, 21, 0x85845DD1 ); P( A, B, C, D, 8, 6, 0x6FA87E4F ); P( D, A, B, C, 15, 10, 0xFE2CE6E0 ); P( C, D, A, B, 6, 15, 0xA3014314 ); P( B, C, D, A, 13, 21, 0x4E0811A1 ); P( A, B, C, D, 4, 6, 0xF7537E82 ); P( D, A, B, C, 11, 10, 0xBD3AF235 ); P( C, D, A, B, 2, 15, 0x2AD7D2BB ); P( B, C, D, A, 9, 21, 0xEB86D391 ); #undef F ctx->state[0] += A; ctx->state[1] += B; ctx->state[2] += C; ctx->state[3] += D; } /* * MD5 process buffer */ void md5_update( md5_context *ctx, const unsigned char *input, size_t ilen ) { size_t fill; uint32_t left; if( ilen <= 0 ) return; left = ctx->total[0] & 0x3F; fill = 64 - left; ctx->total[0] += (uint32_t) ilen; ctx->total[0] &= 0xFFFFFFFF; if( ctx->total[0] < (uint32_t) ilen ) ctx->total[1]++; if( left && ilen >= fill ) { memcpy( (void *) (ctx->buffer + left), input, fill ); md5_process( ctx, ctx->buffer ); input += fill; ilen -= fill; left = 0; } while( ilen >= 64 ) { md5_process( ctx, input ); input += 64; ilen -= 64; } if( ilen > 0 ) { memcpy( (void *) (ctx->buffer + left), input, ilen ); } } static const unsigned char md5_padding[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* * MD5 final digest */ void md5_finish( md5_context *ctx, unsigned char output[16] ) { uint32_t last, padn; uint32_t high, low; unsigned char msglen[8]; high = ( ctx->total[0] >> 29 ) | ( ctx->total[1] << 3 ); low = ( ctx->total[0] << 3 ); PUT_UINT32_LE( low, msglen, 0 ); PUT_UINT32_LE( high, msglen, 4 ); last = ctx->total[0] & 0x3F; padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); md5_update( ctx, md5_padding, padn ); md5_update( ctx, msglen, 8 ); PUT_UINT32_LE( ctx->state[0], output, 0 ); PUT_UINT32_LE( ctx->state[1], output, 4 ); PUT_UINT32_LE( ctx->state[2], output, 8 ); PUT_UINT32_LE( ctx->state[3], output, 12 ); } /* * output = MD5( input buffer ) */ void md5( const unsigned char *input, size_t ilen, unsigned char output[16] ) { md5_context ctx; md5_starts( &ctx ); md5_update( &ctx, input, ilen ); md5_finish( &ctx, output ); memset( &ctx, 0, sizeof( md5_context ) ); } inadyn-2.8.1/src/openssl.c000066400000000000000000000157021400562756000154340ustar00rootroot00000000000000/* OpenSSL interface for optional HTTPS functions * * Copyright (C) 2014-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "log.h" #include "http.h" #include "ssl.h" int ssl_init(void) { #if OPENSSL_VERSION_NUMBER < 0x10100000L SSL_library_init(); SSL_load_error_strings(); OpenSSL_add_all_algorithms(); #endif return 0; } void ssl_exit(void) { #if OPENSSL_VERSION_NUMBER < 0x10100000L ERR_free_strings(); EVP_cleanup(); #endif } static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) { char buf[256]; X509 *cert; int err, depth; cert = X509_STORE_CTX_get_current_cert(ctx); err = X509_STORE_CTX_get_error(ctx); depth = X509_STORE_CTX_get_error_depth(ctx); X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf)); /* * Catch a too long certificate chain. The depth limit set using * SSL_CTX_set_verify_depth() is by purpose set to "limit+1" so * that whenever the "depth>verify_depth" condition is met, we * have violated the limit and want to log this error condition. * We must do it here, because the CHAIN_TOO_LONG error would not * be found explicitly; only errors introduced by cutting off the * additional certificates would be logged. */ if (depth > 100) { preverify_ok = 0; err = X509_V_ERR_CERT_CHAIN_TOO_LONG; X509_STORE_CTX_set_error(ctx, err); } if (!preverify_ok) { logit(LOG_ERR, "Certificate verification error:num=%d:%s:depth=%d:%s", err, X509_verify_cert_error_string(err), depth, buf); if (broken_rtc && err == X509_V_ERR_CERT_NOT_YET_VALID) preverify_ok = 1; } /* * At this point, err contains the last verification error. We can use * it for something special */ if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT)) { X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf)); logit(LOG_ERR, "issuer= %s", buf); } if (secure_ssl) return preverify_ok; return 1; } static int ssl_set_ca_location(http_t *client) { int ret; /* A user defined CA PEM bundle overrides any built-ins or fall-backs */ if (ca_trust_file) { ret = SSL_CTX_load_verify_locations(client->ssl_ctx, ca_trust_file, NULL); goto done; } ret = SSL_CTX_set_default_verify_paths(client->ssl_ctx); if (ret < 1) ret = SSL_CTX_load_verify_locations(client->ssl_ctx, CAFILE1, NULL); if (ret < 1) ret = SSL_CTX_load_verify_locations(client->ssl_ctx, CAFILE2, NULL); done: if (ret < 1) return 1; return 0; } static int ssl_error_cb(const char *str, size_t len, void *data) { size_t sz; char buf[512]; memset(buf, 0, sizeof(buf)); sz = len < sizeof(buf) ? len : sizeof(buf) - 1; memcpy(buf, str, sz); logit(LOG_ERR, "OpenSSL error: %s", buf); return 0; } static void ssl_check_error(void) { ERR_print_errors_cb(ssl_error_cb, NULL); } int ssl_open(http_t *client, char *msg) { const char *sn; char buf[512]; X509 *cert; int rc; if (!client->ssl_enabled) return tcp_init(&client->tcp, msg); tcp_set_port(&client->tcp, HTTPS_DEFAULT_PORT); DO(tcp_init(&client->tcp, msg)); logit(LOG_INFO, "%s, initiating HTTPS ...", msg); client->ssl_ctx = SSL_CTX_new(SSLv23_client_method()); if (!client->ssl_ctx) return RC_HTTPS_OUT_OF_MEMORY; /* POODLE, only allow TLSv1.x or later */ #ifndef OPENSSL_NO_EC SSL_CTX_set_options(client->ssl_ctx, SSL_OP_SINGLE_ECDH_USE | SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION); #else SSL_CTX_set_options(client->ssl_ctx, SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION); #endif SSL_CTX_set_verify(client->ssl_ctx, SSL_VERIFY_PEER, verify_callback); SSL_CTX_set_verify_depth(client->ssl_ctx, 150); /* Try to figure out location of trusted CA certs on system */ if (ssl_set_ca_location(client)) return RC_HTTPS_NO_TRUSTED_CA_STORE; client->ssl = SSL_new(client->ssl_ctx); if (!client->ssl) return RC_HTTPS_OUT_OF_MEMORY; /* SSL SNI support: tell the servername we want to speak to */ http_get_remote_name(client, &sn); if (!SSL_set_tlsext_host_name(client->ssl, sn)) return RC_HTTPS_SNI_ERROR; SSL_set_fd(client->ssl, client->tcp.socket); rc = SSL_connect(client->ssl); if (rc < 0) { ssl_check_error(); return RC_HTTPS_FAILED_CONNECT; } logit(LOG_INFO, "SSL connection using %s", SSL_get_cipher(client->ssl)); cert = SSL_get_peer_certificate(client->ssl); if (!cert) return RC_HTTPS_FAILED_GETTING_CERT; if (SSL_get_verify_result(client->ssl) == X509_V_OK) logit(LOG_DEBUG, "Certificate OK"); X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf)); logit(LOG_INFO, "SSL server cert subject: %s", buf); X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf)); logit(LOG_INFO, "SSL server cert issuer: %s", buf); X509_free(cert); return 0; } int ssl_close(http_t *client) { if (client->ssl_enabled) { if (client->ssl) { /* SSL/TLS close_notify */ SSL_shutdown(client->ssl); /* Clean up. */ SSL_free(client->ssl); client->ssl = NULL; } if (client->ssl_ctx) { SSL_CTX_free(client->ssl_ctx); client->ssl_ctx = NULL; } } return tcp_exit(&client->tcp); } int ssl_send(http_t *client, const char *buf, int len) { int rc, err = SSL_ERROR_NONE; if (!client->ssl_enabled) return tcp_send(&client->tcp, buf, len); do { ERR_clear_error(); rc = SSL_write(client->ssl, buf, len); if (rc <= 0) err = SSL_get_error(client->ssl, rc); } while (err == SSL_ERROR_WANT_WRITE); if (rc <= 0) { ssl_check_error(); return RC_HTTPS_SEND_ERROR; } logit(LOG_DEBUG, "Successfully sent HTTPS request!"); return 0; } int ssl_recv(http_t *client, char *buf, int buf_len, int *recv_len) { int rc, err, len = 0; if (!client->ssl_enabled) return tcp_recv(&client->tcp, buf, buf_len, recv_len); err = SSL_ERROR_NONE; do { ERR_clear_error(); rc = SSL_read(client->ssl, buf + len, buf_len - len); if (rc > 0) { len += rc; } else { err = SSL_get_error(client->ssl, rc); } } while (rc > 0 || err == SSL_ERROR_WANT_READ); if (rc < 0) { ssl_check_error(); return RC_HTTPS_RECV_ERROR; } *recv_len = len; logit(LOG_DEBUG, "Successfully received HTTPS response (%d/%d bytes)!", *recv_len, buf_len); return 0; } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/src/os.c000066400000000000000000000154061400562756000143730ustar00rootroot00000000000000/* * Copyright (C) 2003-2004 Narcis Ilisei * Copyright (C) 2006 Steve Horbachuk * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include /* dirname() */ #include #include #include #include /* fopen() et al */ #include /* atoi() */ #include "log.h" #include "cache.h" static void *param = NULL; /** * Execute shell script on successful update. * @cmd: Full path to script or command to run * @ip: IP address to set as %INADYN_IP env. variable * @name: String to set as %INADYN_HOSTNAME env. variable * @event:Event name to set as %INADYN_EVENT env. variable * @error:Error code to set as %INADYN_ERROR env. variable * * If inadyn has been started with the --iface=IFNAME command line * option the IFNAME is sent to the script as %INADYN_IFACE. * * Returns: * Posix %OK(0), or %RC_OS_FORK_FAILURE on vfork() failure */ int os_shell_execute(char *cmd, char *ip, char *name, char *event, int error) { int rc = 0; int child; char errbuf[11]; child = vfork(); switch (child) { case 0: snprintf(errbuf, sizeof(errbuf), "%d", error); setenv("INADYN_IP", ip, 1); setenv("INADYN_HOSTNAME", name, 1); setenv("INADYN_EVENT", event, 1); setenv("INADYN_ERROR", errbuf, 1); setenv("INADYN_ERROR_MESSAGE", error_str(error), 1); if (iface) setenv("INADYN_IFACE", iface, 1); execl("/bin/sh", "sh", "-c", cmd, (char *)0); exit(1); break; case -1: rc = RC_OS_FORK_FAILURE; break; default: break; } return rc; } /** * unix_signal_handler - Signal handler * @signo: Signal number * * Handler for registered/known signals. Most others will terminate the * daemon. * * NOTE: * Since printf() is one of the possible back-ends of logit(), and * printf() is not one of the safe syscalls to be used, according to * POSIX signal(7). The calls are commented, since they are most likely * also only needed for debugging. */ static void unix_signal_handler(int signo) { ddns_t *ctx = (ddns_t *)param; if (ctx == NULL) return; switch (signo) { case SIGHUP: ctx->cmd = CMD_RESTART; break; case SIGINT: case SIGTERM: ctx->cmd = CMD_STOP; break; case SIGUSR1: ctx->cmd = CMD_FORCED_UPDATE; break; case SIGUSR2: ctx->cmd = CMD_CHECK_NOW; break; default: break; } } /* * Set SIGCHLD to 'ignore', i.e., children are automatically reaped, * as of POSIX.1-2001. This is fine since we are (currently) not * interested in their exit status. */ static int os_install_child_handler(void) { static int installed = 0; int rc = 0; if (!installed) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); #ifdef SA_RESTART sa.sa_flags |= SA_RESTART; #endif sa.sa_handler = SIG_IGN; rc = (sigemptyset(&sa.sa_mask) || sigaddset(&sa.sa_mask, SIGCHLD) || sigaction(SIGCHLD, &sa, NULL)); installed = 1; } if (rc) { logit(LOG_WARNING, "Failed installing signal handler: %s", strerror(errno)); return RC_OS_INSTALL_SIGHANDLER_FAILED; } return 0; } /** * Install signal handler for signals HUP, INT, TERM and USR1 * * Also block exactly the handled signals, only for the duration * of the handler. All other signals are left alone. */ int os_install_signal_handler(void *ctx) { static int installed = 0; int rc = 0; if (!installed) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); #ifdef SA_RESTART sa.sa_flags |= SA_RESTART; #endif sa.sa_handler = unix_signal_handler; rc = (sigemptyset(&sa.sa_mask) || sigaddset(&sa.sa_mask, SIGHUP) || sigaddset(&sa.sa_mask, SIGINT) || sigaddset(&sa.sa_mask, SIGTERM) || sigaddset(&sa.sa_mask, SIGUSR1) || sigaddset(&sa.sa_mask, SIGUSR2) || sigaction(SIGHUP, &sa, NULL) || sigaction(SIGINT, &sa, NULL) || sigaction(SIGUSR1, &sa, NULL) || sigaction(SIGUSR2, &sa, NULL) || sigaction(SIGTERM, &sa, NULL)); installed = 1; } if (script_exec) os_install_child_handler(); if (rc) { logit(LOG_WARNING, "Failed installing signal handler: %s", strerror(errno)); return RC_OS_INSTALL_SIGHANDLER_FAILED; } param = ctx; return 0; } static int pid_alive(pid_t pid) { return !(kill(pid, 0) && errno == ESRCH); } static pid_t getpid_from_pidfile(char *pidfn) { FILE *fp; pid_t pid = 0; fp = fopen(pidfn, "r"); if (fp) { char buf[20]; if (fgets(buf, sizeof(buf), fp)) { pid = atoi(buf); } fclose(fp); } return pid; } /* * Check file system permissions * * Try to create PID file directory and cache file repository. Check if * we are allowed to write to them. This to ensure we can both signal * ACK to a SIGHUP and to ensure we do not cause op to have their DDNS * provider lock them out for excessive updates. */ int os_check_perms(void) { /* Create files with permissions 0644 */ umask(S_IWGRP | S_IWOTH); if ((mkpath(cache_dir, 0755) && errno != EEXIST) || access(cache_dir, W_OK)) { logit(LOG_WARNING, "No write permission to %s: %s", cache_dir, strerror(errno)); logit(LOG_WARNING, "Cannot guarantee DDNS server won't lock you out for excessive updates."); } /* Handle --no-pidfile case as well, check for "" */ if (pidfile_name && pidfile_name[0]) { char pidfn[strlen(RUNSTATEDIR) + strlen(pidfile_name) + 6]; char *pidfile_dir; if (pidfile_name[0] != '/') snprintf(pidfn, sizeof(pidfn), "%s/%s.pid", RUNSTATEDIR, pidfile_name); else strlcpy(pidfn, pidfile_name, sizeof(pidfn)); if (!access(pidfn, F_OK)) { pid_t pid = getpid_from_pidfile(pidfn); if (pid > 0 && pid != getpid() && pid_alive(pid)) { logit(LOG_ERR, "PID file %s already exists, %s already running?", pidfn, prognm); return RC_PIDFILE_EXISTS_ALREADY; } } pidfile_dir = dirname(strdupa(pidfn)); if (access(pidfile_dir, F_OK)) { if (mkpath(pidfile_dir, 0755) && errno != EEXIST) logit(LOG_ERR, "No write permission to %s, aborting.", pidfile_dir); } } return 0; } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/src/plugin.c000066400000000000000000000137731400562756000152550ustar00rootroot00000000000000/* Simplistic plugin support for DDNS service providers * * Copyright (c) 2012-2020 Joachim Nilsson * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "config.h" #include #include /* dlopen() et al */ #include /* readdir() et al */ #include #ifdef __CYGWIN__ #include #include #endif #include "ddns.h" static char *plugpath = NULL; /* Set by first load. */ static TAILQ_HEAD(, ddns_system) plugins = TAILQ_HEAD_INITIALIZER(plugins); int plugin_register(ddns_system_t *plugin) { if (!plugin) { errno = EINVAL; return 1; } if (!plugin->name) { char *dli_fname = NULL; #ifdef __CYGWIN__ char posix_path[MAX_PATH]; char path[MAX_PATH]; MEMORY_BASIC_INFORMATION mbi; VirtualQuery((void*)&plugin, &mbi, sizeof(mbi)); GetModuleFileNameA((HINSTANCE)mbi.AllocationBase, path, MAX_PATH); cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_RELATIVE, path, posix_path, MAX_PATH); dli_fname = posix_path; #else Dl_info info; if (dladdr(plugin, &info)) dli_fname = (char *)info.dli_fname; #endif if (!dli_fname) plugin->name = "unknown"; else plugin->name = (char *)dli_fname; } /* Already registered? */ if (plugin_find(plugin->name, 0)) { logit(LOG_DEBUG, "... %s already loaded.", plugin->name); return 0; } TAILQ_INSERT_TAIL(&plugins, plugin, link); return 0; } int plugin_unregister(ddns_system_t *plugin) { TAILQ_REMOVE(&plugins, plugin, link); /* XXX: Unfinished, add cleanup code here! */ return 0; } static ddns_system_t *search_plugin(const char *name, int loose) { ddns_system_t *p, *tmp; if (loose) { PLUGIN_ITERATOR(p, tmp) { if (strcasestr(p->name, name)) return p; } return NULL; } PLUGIN_ITERATOR(p, tmp) { if (!strcasecmp(p->name, name)) return p; } return NULL; } /** * plugin_find - Find a plugin by name * @name: With or without path, or .so extension * @loose: Use substring match when looking for plugin * * This function uses an opporunistic search for a suitable plugin and * returns the first match. Albeit with at least some measure of * heuristics. * * First it checks for an exact match. If no match is found and @name * starts with a slash the search ends. Otherwise a new search with the * plugin path prepended to @name is made. Also, if @name does not end * with .so it too is added to @name before searching. * * Returns: * On success the pointer to the matching &ddns_system_t is returned, * otherwise %NULL is returned. */ ddns_system_t *plugin_find(const char *name, int loose) { char *tmp, *ptr; ddns_system_t *p; if (!name) { errno = EINVAL; return NULL; } /* Check for multiple instances of plugin */ tmp = strdup(name); if (!tmp) return NULL; ptr = strchr(tmp, ':'); if (ptr) *ptr = 0; name = tmp; p = search_plugin(name, loose); if (p) { free(tmp); return p; } if (plugpath && name[0] != '/') { int noext; char *path; size_t len = strlen(plugpath) + strlen(name) + 5; path = malloc(len); if (!path) { free(tmp); return NULL; } noext = strcmp(name + strlen(name) - 3, ".so"); snprintf(path, len, "%s%s%s%s", plugpath, plugpath[strlen(plugpath) - 1] == '/' ? "" : "/", name, noext ? ".so" : ""); p = search_plugin(path, loose); free(path); if (p) { free(tmp); return p; } } free(tmp); errno = ENOENT; return NULL; } /* Private daemon API *******************************************************/ #if o /** * load_one - Load one plugin * @path: Path to finit plugins, usually %PLUGIN_PATH * @name: Name of plugin, optionally ending in ".so" * * Loads a plugin from @path/@name[.so]. Note, if ".so" is missing from * the plugin @name it is added before attempting to load. * * It is up to the plugin itself ot register itself as a "ctor" with the * %PLUGIN_INIT macro so that plugin_register() is called automatically. * * Returns: * POSIX OK(0) on success, non-zero otherwise. */ static int load_one(char *path, char *name) { int noext; char plugin[256]; void *handle; if (!path || !name) { errno = EINVAL; return 1; } /* Compose full path, with optional .so extension, to plugin */ noext = strcmp(name + strlen(name) - 3, ".so"); snprintf(plugin, sizeof(plugin), "%s/%s%s", path, name, noext ? ".so" : ""); logit(LOG_DEBUG, "Loading plugin %s ...", basename(plugin)); handle = dlopen(plugin, RTLD_LAZY | RTLD_GLOBAL); if (!handle) { logit(LOG_ERR, "Failed loading plugin %s: %s", plugin, dlerror()); return 1; } return 0; } int plugin_load_all(char *path) { int fail = 0; DIR *dp = opendir(path); struct dirent *entry; if (!dp) { logit(LOG_ERR, "Failed, cannot open plugin directory %s: %s", path, strerror(errno)); return 1; } plugpath = path; while ((entry = readdir(dp))) { if (entry->d_name[0] == '.') continue; /* Skip . and .. directories */ if (load_one(path, entry->d_name)) fail++; } closedir(dp); return fail; } #endif /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */ inadyn-2.8.1/src/sha1.c000066400000000000000000000211301400562756000145750ustar00rootroot00000000000000/* FIPS-180-1 compliant SHA-1 implementation * * Copyright (C) 2006-2010, Brainspark B.V. * * This file is part of PolarSSL (http://www.polarssl.org) * Lead Maintainer: Paul Bakker * * All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ /* * The SHA-1 standard was published by NIST in 1993. * * http://www.itl.nist.gov/fipspubs/fip180-1.htm */ #include "sha1.h" /* * 32-bit integer manipulation macros (big endian) */ #ifndef GET_ULONG_BE #define GET_ULONG_BE(n,b,i) \ { \ (n) = ( (unsigned long) (b)[(i) ] << 24 ) \ | ( (unsigned long) (b)[(i) + 1] << 16 ) \ | ( (unsigned long) (b)[(i) + 2] << 8 ) \ | ( (unsigned long) (b)[(i) + 3] ); \ } #endif #ifndef PUT_ULONG_BE #define PUT_ULONG_BE(n,b,i) \ { \ (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ (b)[(i) + 3] = (unsigned char) ( (n) ); \ } #endif /* * SHA-1 context setup */ void sha1_starts( sha1_context *ctx ) { ctx->total[0] = 0; ctx->total[1] = 0; ctx->state[0] = 0x67452301; ctx->state[1] = 0xEFCDAB89; ctx->state[2] = 0x98BADCFE; ctx->state[3] = 0x10325476; ctx->state[4] = 0xC3D2E1F0; } static void sha1_process( sha1_context *ctx, const unsigned char data[64] ) { unsigned long temp, W[16], A, B, C, D, E; GET_ULONG_BE( W[ 0], data, 0 ); GET_ULONG_BE( W[ 1], data, 4 ); GET_ULONG_BE( W[ 2], data, 8 ); GET_ULONG_BE( W[ 3], data, 12 ); GET_ULONG_BE( W[ 4], data, 16 ); GET_ULONG_BE( W[ 5], data, 20 ); GET_ULONG_BE( W[ 6], data, 24 ); GET_ULONG_BE( W[ 7], data, 28 ); GET_ULONG_BE( W[ 8], data, 32 ); GET_ULONG_BE( W[ 9], data, 36 ); GET_ULONG_BE( W[10], data, 40 ); GET_ULONG_BE( W[11], data, 44 ); GET_ULONG_BE( W[12], data, 48 ); GET_ULONG_BE( W[13], data, 52 ); GET_ULONG_BE( W[14], data, 56 ); GET_ULONG_BE( W[15], data, 60 ); #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) #define R(t) \ ( \ temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ \ W[(t - 14) & 0x0F] ^ W[ t & 0x0F], \ ( W[t & 0x0F] = S(temp,1) ) \ ) #define P(a,b,c,d,e,x) \ { \ e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \ } A = ctx->state[0]; B = ctx->state[1]; C = ctx->state[2]; D = ctx->state[3]; E = ctx->state[4]; #define F(x,y,z) (z ^ (x & (y ^ z))) #define K 0x5A827999 P( A, B, C, D, E, W[0] ); P( E, A, B, C, D, W[1] ); P( D, E, A, B, C, W[2] ); P( C, D, E, A, B, W[3] ); P( B, C, D, E, A, W[4] ); P( A, B, C, D, E, W[5] ); P( E, A, B, C, D, W[6] ); P( D, E, A, B, C, W[7] ); P( C, D, E, A, B, W[8] ); P( B, C, D, E, A, W[9] ); P( A, B, C, D, E, W[10] ); P( E, A, B, C, D, W[11] ); P( D, E, A, B, C, W[12] ); P( C, D, E, A, B, W[13] ); P( B, C, D, E, A, W[14] ); P( A, B, C, D, E, W[15] ); P( E, A, B, C, D, R(16) ); P( D, E, A, B, C, R(17) ); P( C, D, E, A, B, R(18) ); P( B, C, D, E, A, R(19) ); #undef K #undef F #define F(x,y,z) (x ^ y ^ z) #define K 0x6ED9EBA1 P( A, B, C, D, E, R(20) ); P( E, A, B, C, D, R(21) ); P( D, E, A, B, C, R(22) ); P( C, D, E, A, B, R(23) ); P( B, C, D, E, A, R(24) ); P( A, B, C, D, E, R(25) ); P( E, A, B, C, D, R(26) ); P( D, E, A, B, C, R(27) ); P( C, D, E, A, B, R(28) ); P( B, C, D, E, A, R(29) ); P( A, B, C, D, E, R(30) ); P( E, A, B, C, D, R(31) ); P( D, E, A, B, C, R(32) ); P( C, D, E, A, B, R(33) ); P( B, C, D, E, A, R(34) ); P( A, B, C, D, E, R(35) ); P( E, A, B, C, D, R(36) ); P( D, E, A, B, C, R(37) ); P( C, D, E, A, B, R(38) ); P( B, C, D, E, A, R(39) ); #undef K #undef F #define F(x,y,z) ((x & y) | (z & (x | y))) #define K 0x8F1BBCDC P( A, B, C, D, E, R(40) ); P( E, A, B, C, D, R(41) ); P( D, E, A, B, C, R(42) ); P( C, D, E, A, B, R(43) ); P( B, C, D, E, A, R(44) ); P( A, B, C, D, E, R(45) ); P( E, A, B, C, D, R(46) ); P( D, E, A, B, C, R(47) ); P( C, D, E, A, B, R(48) ); P( B, C, D, E, A, R(49) ); P( A, B, C, D, E, R(50) ); P( E, A, B, C, D, R(51) ); P( D, E, A, B, C, R(52) ); P( C, D, E, A, B, R(53) ); P( B, C, D, E, A, R(54) ); P( A, B, C, D, E, R(55) ); P( E, A, B, C, D, R(56) ); P( D, E, A, B, C, R(57) ); P( C, D, E, A, B, R(58) ); P( B, C, D, E, A, R(59) ); #undef K #undef F #define F(x,y,z) (x ^ y ^ z) #define K 0xCA62C1D6 P( A, B, C, D, E, R(60) ); P( E, A, B, C, D, R(61) ); P( D, E, A, B, C, R(62) ); P( C, D, E, A, B, R(63) ); P( B, C, D, E, A, R(64) ); P( A, B, C, D, E, R(65) ); P( E, A, B, C, D, R(66) ); P( D, E, A, B, C, R(67) ); P( C, D, E, A, B, R(68) ); P( B, C, D, E, A, R(69) ); P( A, B, C, D, E, R(70) ); P( E, A, B, C, D, R(71) ); P( D, E, A, B, C, R(72) ); P( C, D, E, A, B, R(73) ); P( B, C, D, E, A, R(74) ); P( A, B, C, D, E, R(75) ); P( E, A, B, C, D, R(76) ); P( D, E, A, B, C, R(77) ); P( C, D, E, A, B, R(78) ); P( B, C, D, E, A, R(79) ); #undef K #undef F ctx->state[0] += A; ctx->state[1] += B; ctx->state[2] += C; ctx->state[3] += D; ctx->state[4] += E; } /* * SHA-1 process buffer */ void sha1_update( sha1_context *ctx, const unsigned char *input, size_t ilen ) { size_t fill; unsigned long left; if( ilen <= 0 ) return; left = ctx->total[0] & 0x3F; fill = 64 - left; ctx->total[0] += (unsigned long) ilen; ctx->total[0] &= 0xFFFFFFFF; if( ctx->total[0] < (unsigned long) ilen ) ctx->total[1]++; if( left && ilen >= fill ) { memcpy( (void *) (ctx->buffer + left), (void *) input, fill ); sha1_process( ctx, ctx->buffer ); input += fill; ilen -= fill; left = 0; } while( ilen >= 64 ) { sha1_process( ctx, input ); input += 64; ilen -= 64; } if( ilen > 0 ) { memcpy( (void *) (ctx->buffer + left), (void *) input, ilen ); } } static const unsigned char sha1_padding[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* * SHA-1 final digest */ void sha1_finish( sha1_context *ctx, unsigned char output[20] ) { unsigned long last, padn; unsigned long high, low; unsigned char msglen[8]; high = ( ctx->total[0] >> 29 ) | ( ctx->total[1] << 3 ); low = ( ctx->total[0] << 3 ); PUT_ULONG_BE( high, msglen, 0 ); PUT_ULONG_BE( low, msglen, 4 ); last = ctx->total[0] & 0x3F; padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); sha1_update( ctx, (unsigned char *) sha1_padding, padn ); sha1_update( ctx, msglen, 8 ); PUT_ULONG_BE( ctx->state[0], output, 0 ); PUT_ULONG_BE( ctx->state[1], output, 4 ); PUT_ULONG_BE( ctx->state[2], output, 8 ); PUT_ULONG_BE( ctx->state[3], output, 12 ); PUT_ULONG_BE( ctx->state[4], output, 16 ); } /* * output = SHA-1( input buffer ) */ void sha1( const unsigned char *input, size_t ilen, unsigned char output[20] ) { sha1_context ctx; sha1_starts( &ctx ); sha1_update( &ctx, input, ilen ); sha1_finish( &ctx, output ); memset( &ctx, 0, sizeof( sha1_context ) ); } inadyn-2.8.1/src/tcp.c000066400000000000000000000164271400562756000145440ustar00rootroot00000000000000/* Interface for TCP functions * * Copyright (C) 2003-2004 Narcis Ilisei * Copyright (C) 2010-2020 Joachim Nilsson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, visit the Free Software Foundation * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "log.h" #include "tcp.h" int tcp_construct(tcp_sock_t *tcp) { ASSERT(tcp); memset(tcp, 0, sizeof(tcp_sock_t)); tcp->initialized = 0; tcp->socket = -1; /* Initialize to 'error', not a possible socket id. */ tcp->timeout = TCP_DEFAULT_TIMEOUT; return 0; } int tcp_destruct(tcp_sock_t *tcp) { ASSERT(tcp); if (tcp->initialized == 1) tcp_exit(tcp); return 0; } static int soerror(int sd) { int code = 0; socklen_t len = sizeof(code); if (getsockopt(sd, SOL_SOCKET, SO_ERROR, &code, &len)) return 1; return errno = code; } /* * In the wonderful world of network programming the manual states that * EINPROGRESS is only a possible error on non-blocking sockets. Real world * experience, however, suggests otherwise. Simply poll() for completion and * then continue. --Joachim */ static int check_error(int sd, int msec) { struct pollfd pfd = { sd, POLLOUT, 0 }; if (EINPROGRESS == errno) { logit(LOG_INFO, "Waiting (%d sec) for three-way handshake to complete ...", msec / 1000); if (poll (&pfd, 1, msec) > 0 && !soerror(sd)) { logit(LOG_INFO, "Connected."); return 0; } } return 1; } static void set_timeouts(int sd, int timeout) { struct timeval sv; memset(&sv, 0, sizeof(sv)); sv.tv_sec = timeout / 1000; sv.tv_usec = (timeout % 1000) * 1000; if (-1 == setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, &sv, sizeof(sv))) logit(LOG_INFO, "Failed setting receive timeout socket option: %s", strerror(errno)); if (-1 == setsockopt(sd, SOL_SOCKET, SO_SNDTIMEO, &sv, sizeof(sv))) logit(LOG_INFO, "Failed setting send timeout socket option: %s", strerror(errno)); } int tcp_init(tcp_sock_t *tcp, char *msg) { int rc = 0; ASSERT(tcp); if (tcp->initialized == 1) return 0; do { int s, sd, tries = 0; char port[10]; char host[NI_MAXHOST]; struct addrinfo hints, *servinfo, *ai; struct sockaddr *sa; socklen_t len; /* remote address */ if (!tcp->remote_host) break; /* Clear DNS cache before calling getaddrinfo(). */ res_init(); /* Obtain address(es) matching host/port */ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_socktype = SOCK_STREAM; /* Stream socket */ hints.ai_flags = AI_NUMERICSERV; /* No service name lookup */ snprintf(port, sizeof(port), "%d", tcp->port); s = getaddrinfo(tcp->remote_host, port, &hints, &servinfo); if (s != 0 || !servinfo) { logit(LOG_WARNING, "Failed resolving hostname %s: %s", tcp->remote_host, gai_strerror(s)); rc = RC_TCP_INVALID_REMOTE_ADDR; break; } ai = servinfo; while (1) { sd = socket(ai->ai_family, SOCK_STREAM, 0); if (sd == -1) { logit(LOG_ERR, "Error creating client socket: %s", strerror(errno)); rc = RC_TCP_SOCKET_CREATE_ERROR; break; } /* Now we try connecting to the server, on connect fail, try next DNS record */ sa = ai->ai_addr; len = ai->ai_addrlen; if (getnameinfo(sa, len, host, sizeof(host), NULL, 0, NI_NUMERICHOST)) goto next; set_timeouts(sd, tcp->timeout); logit(LOG_INFO, "%s, %sconnecting to %s([%s]:%d)", msg, tries ? "re" : "", tcp->remote_host, host, tcp->port); if (connect(sd, sa, len) && check_error(sd, tcp->timeout)) { next: tries++; ai = ai->ai_next; if (ai) { logit(LOG_INFO, "Failed connecting to that server: %s", errno != EINPROGRESS ? strerror(errno) : "retrying ..."); close(sd); continue; } logit(LOG_WARNING, "Failed connecting to %s: %s", tcp->remote_host, strerror(errno)); close(sd); rc = RC_TCP_CONNECT_FAILED; } else { tcp->socket = sd; tcp->initialized = 1; } break; } freeaddrinfo(servinfo); } while (0); if (rc) { tcp_exit(tcp); return rc; } return 0; } int tcp_exit(tcp_sock_t *tcp) { ASSERT(tcp); if (!tcp->initialized) return 0; if (tcp->socket > -1) { close(tcp->socket); tcp->socket = -1; } tcp->initialized = 0; return 0; } int tcp_send(tcp_sock_t *tcp, const char *buf, int len) { ASSERT(tcp); if (!tcp->initialized) return RC_TCP_OBJECT_NOT_INITIALIZED; again: if (send(tcp->socket, buf, len, 0) == -1) { int err = errno; if(err == EAGAIN || err == EWOULDBLOCK){ goto again; } logit(LOG_WARNING, "Network error while sending query/update: %s", strerror(errno)); return RC_TCP_SEND_ERROR; } return 0; } int tcp_recv(tcp_sock_t *tcp, char *buf, int len, int *recv_len) { int rc = 0; int remaining_bytes = len; int total_bytes = 0; ASSERT(tcp); ASSERT(buf); ASSERT(recv_len); if (!tcp->initialized) return RC_TCP_OBJECT_NOT_INITIALIZED; while (remaining_bytes > 0) { int bytes; int err = 0; int chunk_size = remaining_bytes > TCP_DEFAULT_READ_CHUNK_SIZE ? TCP_DEFAULT_READ_CHUNK_SIZE : remaining_bytes; bytes = recv(tcp->socket, buf + total_bytes, chunk_size, 0); err = errno; if(bytes == -1 && (err == EAGAIN || err == EWOULDBLOCK)){ continue; } if (bytes < 0) { logit(LOG_WARNING, "Network error while waiting for reply: %s", strerror(errno)); rc = RC_TCP_RECV_ERROR; break; } if (bytes == 0) { if (total_bytes == 0) rc = RC_TCP_RECV_ERROR; break; } total_bytes += bytes; remaining_bytes = len - total_bytes; } *recv_len = total_bytes; return rc; } int tcp_set_port(tcp_sock_t *tcp, int port) { ASSERT(tcp); if (port < 0 || port > TCP_SOCKET_MAX_PORT) return RC_TCP_BAD_PARAMETER; tcp->port = port; return 0; } int tcp_get_port(tcp_sock_t *tcp, int *port) { ASSERT(tcp); ASSERT(port); *port = tcp->port; return 0; } int tcp_set_remote_name(tcp_sock_t *tcp, const char *name) { ASSERT(tcp); tcp->remote_host = name; return 0; } int tcp_get_remote_name(tcp_sock_t *tcp, const char **name) { ASSERT(tcp); ASSERT(name); *name = tcp->remote_host; return 0; } int tcp_set_remote_timeout(tcp_sock_t *tcp, int timeout) { ASSERT(tcp); tcp->timeout = timeout; return 0; } int tcp_get_remote_timeout(tcp_sock_t *tcp, int *timeout) { ASSERT(tcp); ASSERT(timeout); *timeout = tcp->timeout; return 0; } /** * Local Variables: * indent-tabs-mode: t * c-file-style: "linux" * End: */