From 76d609582ec8f6c342fdd5141a9cb803fb1bd492 Mon Sep 17 00:00:00 2001 From: "Martinski@GitHub" <119833648+Martinski4GitHub@users.noreply.github.com> Date: Tue, 2 Jul 2024 18:28:27 -0700 Subject: [PATCH 1/9] Fixed comparison of F/W versions Fixed bugs in the code that were incorrectly comparing versions between the currently installed F/W with the next F/W update available. --- release/src/router/rom/webs_scripts/merlin_webs_update.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release/src/router/rom/webs_scripts/merlin_webs_update.sh b/release/src/router/rom/webs_scripts/merlin_webs_update.sh index 2567671f9b6..3c26ff0e977 100755 --- a/release/src/router/rom/webs_scripts/merlin_webs_update.sh +++ b/release/src/router/rom/webs_scripts/merlin_webs_update.sh @@ -65,9 +65,9 @@ else newfirm=1 elif [ "$current_base" -eq "$firmbase" ] && [ "$current_firm" -lt "$firmver" ]; then newfirm=1 - elif [ "$current_base" -eq "$firmbase" ] && [ "$current_firm" -eq "$current_firm" ] && [ "$current_buildno" -lt "$buildno" ]; then + elif [ "$current_base" -eq "$firmbase" ] && [ "$current_firm" -eq "$firmver" ] && [ "$current_buildno" -lt "$buildno" ]; then newfirm=1 - elif [ "$current_base" -eq "$firmbase" ] && [ "$current_firm" -eq "$current_firm" ] && [ "$current_buildno" -eq "$buildno" ] && [ "$current_extendno" -lt "$lextendno" ]; then + elif [ "$current_base" -eq "$firmbase" ] && [ "$current_firm" -eq "$firmver" ] && [ "$current_buildno" -eq "$buildno" ] && [ "$current_extendno" -lt "$lextendno" ]; then newfirm=1 else newfirm=0 From 3e36b02cb265c7c3397d02f94cbd47ea243e5ebb Mon Sep 17 00:00:00 2001 From: Eric Sauvageau Date: Tue, 9 Jul 2024 16:03:04 -0400 Subject: [PATCH 2/9] webui: rename venderIcon for vendorIcon to match with upstream 3006 changes --- release/src/router/www/Advanced_TOR_Content.asp | 6 +++--- release/src/router/www/DNSDirector.asp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/release/src/router/www/Advanced_TOR_Content.asp b/release/src/router/www/Advanced_TOR_Content.asp index e6bc51429ec..13621fa7b1d 100644 --- a/release/src/router/www/Advanced_TOR_Content.asp +++ b/release/src/router/www/Advanced_TOR_Content.asp @@ -89,9 +89,9 @@ function show_tor_redir_list(){ code += '
'; } else if(deviceVender != "" ) { - var venderIconClassName = getVenderIconClassName(deviceVender.toLowerCase()); - if(venderIconClassName != "") { - code += '
'; + var VendorIconClassName = getVendorIconClassName(deviceVender.toLowerCase()); + if(VendorIconClassName != "") { + code += '
'; } else { code += '
'; diff --git a/release/src/router/www/DNSDirector.asp b/release/src/router/www/DNSDirector.asp index 6c4094f4162..00be9e085cb 100644 --- a/release/src/router/www/DNSDirector.asp +++ b/release/src/router/www/DNSDirector.asp @@ -224,9 +224,9 @@ function show_dnsfilter_list(){ code += '
'; } else if(deviceVender != "" ) { - var venderIconClassName = getVenderIconClassName(deviceVender.toLowerCase()); - if(venderIconClassName != "" && !downsize_4m_support) { - code += '
'; + var VendorIconClassName = getVendorIconClassName(deviceVender.toLowerCase()); + if(VendorIconClassName != "" && !downsize_4m_support) { + code += '
'; } else { code += '
'; From 03a4bee0799f3f3b74b213a1faa2747e59374bce Mon Sep 17 00:00:00 2001 From: Eric Sauvageau Date: Tue, 9 Jul 2024 16:04:32 -0400 Subject: [PATCH 3/9] Updated documentation --- Changelog-3006.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Changelog-3006.txt b/Changelog-3006.txt index eb528f917ee..7ef8b301864 100644 --- a/Changelog-3006.txt +++ b/Changelog-3006.txt @@ -1,6 +1,11 @@ Asuswrt-Merlin 3006.xxx Changelog ================================= +3006.102.xx (xx-xxx-xxxx) + - FIXED: DNSDirector and Tor pages would fail to properly load + in some environment. + + 3006.102.1 (28-Jun-2024) This is the initial release of Asuswrt-Merlin based on From eda9a93f2af2f7d3aff6161a3ec4703fc3dad8cb Mon Sep 17 00:00:00 2001 From: Eric Sauvageau Date: Sat, 13 Jul 2024 13:28:18 -0400 Subject: [PATCH 4/9] webui: added missing UPnP options on devices with Multiservice WAN support --- .../sysdep/BM68/www/Advanced_WAN_Content.asp | 65 ++++++++++++++++++- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/release/src/router/www/sysdep/BM68/www/Advanced_WAN_Content.asp b/release/src/router/www/sysdep/BM68/www/Advanced_WAN_Content.asp index 2febb47d70c..59558ae2a2f 100644 --- a/release/src/router/www/sysdep/BM68/www/Advanced_WAN_Content.asp +++ b/release/src/router/www/sysdep/BM68/www/Advanced_WAN_Content.asp @@ -1602,6 +1602,8 @@ function initial(){ showhide("dnssec_strict_tr", "<% nvram_get("dnssec_enable"); %>" == "1" ? 1 : 0); } + display_upnp_options(); + if(parent.webWrapper){ $("#DNS_Assign_splitLine").addClass("splitLine_dns_bussiness"); $("#DNS_Assign_desc").addClass("assign_dns_bussiness"); @@ -1616,6 +1618,17 @@ function initial(){ } +function display_upnp_options(){ + document.getElementById("upnp_range_int").style.display = (document.form.wan_upnp_enable[0].checked) ? "" : "none"; + document.getElementById("upnp_range_ext").style.display = (document.form.wan_upnp_enable[0].checked) ? "" : "none"; + document.getElementById("upnp_secure_tr").style.display = (document.form.wan_upnp_enable[0].checked) ? "" : "none"; + if (igd2_support) { + document.getElementById("upnp_pinhole").style.display = (document.form.wan_upnp_enable[0].checked) ? "" : "none"; + } else { + document.getElementById("upnp_pinhole").style.display = "none"; + } +} + function change_wan_unit(obj){ if(!dualWAN_support) return; @@ -1985,6 +1998,20 @@ function validForm(){ } } + if (document.form.wan_upnp_enable[0].checked) { + if((!validator.numberRange(document.form.upnp_min_port_int, 1, 65535)) + || (!validator.numberRange(document.form.upnp_max_port_int, 1, 65535)) + || (!validator.numberRange(document.form.upnp_min_port_ext, 1, 65535)) + || (!validator.numberRange(document.form.upnp_max_port_ext, 1, 65535))) { + return false; + } + if((parseInt(document.form.upnp_max_port_int.value) < parseInt(document.form.upnp_min_port_int.value)) + || (parseInt(document.form.upnp_max_port_ext.value) < parseInt(document.form.upnp_min_port_ext.value))) { + alert("Invalid UPNP ports! First port must be lower than last port value."); + return false; + } + } + if(wan_bonding_support){ var msg_dualwan = "<#WANAggregation_disable_dualwan#>"; var msg_both = "<#WANAggregation_disable_IPTVDualWAN#>"; @@ -3521,12 +3548,44 @@ function change_wizard(o, id){ - <#BasicConfig_EnableMediaServer_itemname#> + Enable UPnP IGD & PCP/NAT-PMP      FAQ + + ><#checkbox_Yes#> + ><#checkbox_No#> + + + + Enable UPnP IGDv2 (IPv6 support) - ><#checkbox_Yes#> - ><#checkbox_No#> + ><#checkbox_Yes#> + ><#checkbox_No#> + + Enable secure UPnP IGD mode + + ><#checkbox_Yes#> + ><#checkbox_No#> + + + + UPNP: Allowed internal port range + + " onkeypress="return validator.isNumber(this,event);"> + to + " onkeypress="return validator.isNumber(this,event);"> + + + + + UPNP: Allowed external port range + + " onkeypress="return validator.isNumber(this,event);"> + to + " onkeypress="return validator.isNumber(this,event);"> + + + <#BasicConfig_EnableMediaServer_itemname#> From 9bf552f4247b38008792aa1f5ca26df5dafb4e68 Mon Sep 17 00:00:00 2001 From: Eric Sauvageau Date: Sat, 13 Jul 2024 13:41:15 -0400 Subject: [PATCH 5/9] webui: WAN multiservice page - disable Asus-hosted DNS server lists, add missing hint if enabling DNSDirector + DNS Privacy Brings the multiservice version of the page more in line with the regular Asuswrt-Merlin WAN page. --- .../router/www/sysdep/BM68/www/Advanced_WAN_Content.asp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/release/src/router/www/sysdep/BM68/www/Advanced_WAN_Content.asp b/release/src/router/www/sysdep/BM68/www/Advanced_WAN_Content.asp index 59558ae2a2f..78ba338e092 100644 --- a/release/src/router/www/sysdep/BM68/www/Advanced_WAN_Content.asp +++ b/release/src/router/www/sysdep/BM68/www/Advanced_WAN_Content.asp @@ -1562,6 +1562,9 @@ function initial(){ } if(dnspriv_support){ + if (dnsfilter_support && "<% nvram_get("dnsfilter_enable_x"); %>" == "1") + document.getElementById("dnsfilter_hint_dnspriv").style.display = ""; + $.getJSON("/dot-servers.json", function(local_data){ var gen_dotPresets = function(data){ $("#dotPresets").children().remove().end().append(""); @@ -1585,6 +1588,7 @@ function initial(){ $("#dot_presets_tr").hide(); }; gen_dotPresets(local_data); +/* $.getJSON("https://nw-dlcdnet.asus.com/plugin/js/dot-servers.json", function(cloud_data){ if(JSON.stringify(local_data) != JSON.stringify(cloud_data)){ @@ -1594,6 +1598,7 @@ function initial(){ } } ); +*/ }); } @@ -3247,7 +3252,7 @@ function updatDNSListOnline(){ return local_data[e]; }); Update_DNS_status(); - +/* $.getJSON("https://nw-dlcdnet.asus.com/plugin/js/DNS_List.json", function(cloud_data){ if(JSON.stringify(local_data) != JSON.stringify(cloud_data)){ @@ -3260,6 +3265,7 @@ function updatDNSListOnline(){ } } ); +*/ }); } @@ -3835,6 +3841,7 @@ function change_wizard(o, id){ + From 0d553f8885b8494f620e02059107a87671df641a Mon Sep 17 00:00:00 2001 From: Eric Sauvageau Date: Sat, 13 Jul 2024 14:20:46 -0400 Subject: [PATCH 6/9] webui: fix icon display on DNS Director device list --- release/src/router/www/DNSDirector.asp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/release/src/router/www/DNSDirector.asp b/release/src/router/www/DNSDirector.asp index 00be9e085cb..625e1127e71 100644 --- a/release/src/router/www/DNSDirector.asp +++ b/release/src/router/www/DNSDirector.asp @@ -209,7 +209,7 @@ function show_dnsfilter_list(){ code +=''; code +=''; - code += '
'; + code += '
'; if(clientList[clientMac] == undefined) { code += '
'; } @@ -218,18 +218,22 @@ function show_dnsfilter_list(){ userIconBase64 = getUploadIcon(clientMac.replace(/\:/g, "")); } if(userIconBase64 != "NoIcon") { - code += '
'; + if(clientList[clientMac].isUserUplaodImg){ + code += '
'; + }else{ + code += '
'; + } } - else if(deviceType != "0" || deviceVender == "") { - code += '
'; + else if(deviceType != "0" || deviceVendor == "") { + code += '
'; } - else if(deviceVender != "" ) { - var VendorIconClassName = getVendorIconClassName(deviceVender.toLowerCase()); - if(VendorIconClassName != "" && !downsize_4m_support) { - code += '
'; + else if(deviceVendor != "" ) { + var vendorIconClassName = getVendorIconClassName(deviceVendor.toLowerCase()); + if(vendorIconClassName != "" && !downsize_4m_support) { + code += '
'; } else { - code += '
'; + code += '
'; } } } From 39198b55c02f0e26f46ab349dca97bbdf44c11b7 Mon Sep 17 00:00:00 2001 From: Eric Sauvageau Date: Sat, 13 Jul 2024 14:21:04 -0400 Subject: [PATCH 7/9] webui: fix code layout on DHCP page --- .../src/router/www/Advanced_DHCP_Content.asp | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/release/src/router/www/Advanced_DHCP_Content.asp b/release/src/router/www/Advanced_DHCP_Content.asp index 39d12a70ff9..de1392aa054 100644 --- a/release/src/router/www/Advanced_DHCP_Content.asp +++ b/release/src/router/www/Advanced_DHCP_Content.asp @@ -390,24 +390,24 @@ function showdhcp_staticlist(){ userIconBase64 = getUploadIcon(clientMac.replace(/\:/g, "")); } if(userIconBase64 != "NoIcon") { - if(clientList[clientMac].isUserUplaodImg){ - code += '
'; - }else{ - code += '
'; - } - } - else if(deviceType != "0" || deviceVendor == "") { - code += '
'; - } - else if(deviceVendor != "" ) { - var vendorIconClassName = getVendorIconClassName(deviceVendor.toLowerCase()); - if(vendorIconClassName != "" && !downsize_4m_support) { - code += '
'; - } - else { - code += '
'; - } - } + if(clientList[clientMac].isUserUplaodImg){ + code += '
'; + }else{ + code += '
'; + } + } + else if(deviceType != "0" || deviceVendor == "") { + code += '
'; + } + else if(deviceVendor != "" ) { + var vendorIconClassName = getVendorIconClassName(deviceVendor.toLowerCase()); + if(vendorIconClassName != "" && !downsize_4m_support) { + code += '
'; + } + else { + code += '
'; + } + } } code += '
'; code += '
' + clientName + '
'; From a1c20e3690ae6819a221ef3e57010480b1b1c9cc Mon Sep 17 00:00:00 2001 From: Eric Sauvageau Date: Wed, 17 Jul 2024 22:16:37 -0400 Subject: [PATCH 8/9] libnss-mdns: added files from git repository --- release/src/router/libnss-mdns/.clang-format | 4 + release/src/router/libnss-mdns/.gitignore | 29 + .../router/libnss-mdns/ACKNOWLEDGEMENTS.md | 9 + release/src/router/libnss-mdns/LICENSE | 510 ++++++++ release/src/router/libnss-mdns/Makefile.am | 136 +++ release/src/router/libnss-mdns/NEWS.md | 181 +++ release/src/router/libnss-mdns/README.md | 221 ++++ release/src/router/libnss-mdns/bootstrap.sh | 21 + release/src/router/libnss-mdns/configure.ac | 95 ++ .../src/router/libnss-mdns/src/avahi-test.c | 51 + release/src/router/libnss-mdns/src/avahi.c | 183 +++ release/src/router/libnss-mdns/src/avahi.h | 62 + release/src/router/libnss-mdns/src/bsdnss.c | 374 ++++++ release/src/router/libnss-mdns/src/map-file | 41 + release/src/router/libnss-mdns/src/nss-test.c | 145 +++ release/src/router/libnss-mdns/src/nss.c | 284 +++++ release/src/router/libnss-mdns/src/nss.h | 52 + release/src/router/libnss-mdns/src/util.c | 336 ++++++ release/src/router/libnss-mdns/src/util.h | 137 +++ .../src/router/libnss-mdns/tests/check_util.c | 1060 +++++++++++++++++ 20 files changed, 3931 insertions(+) create mode 100644 release/src/router/libnss-mdns/.clang-format create mode 100644 release/src/router/libnss-mdns/.gitignore create mode 100644 release/src/router/libnss-mdns/ACKNOWLEDGEMENTS.md create mode 100644 release/src/router/libnss-mdns/LICENSE create mode 100644 release/src/router/libnss-mdns/Makefile.am create mode 100644 release/src/router/libnss-mdns/NEWS.md create mode 100644 release/src/router/libnss-mdns/README.md create mode 100755 release/src/router/libnss-mdns/bootstrap.sh create mode 100644 release/src/router/libnss-mdns/configure.ac create mode 100644 release/src/router/libnss-mdns/src/avahi-test.c create mode 100644 release/src/router/libnss-mdns/src/avahi.c create mode 100644 release/src/router/libnss-mdns/src/avahi.h create mode 100644 release/src/router/libnss-mdns/src/bsdnss.c create mode 100644 release/src/router/libnss-mdns/src/map-file create mode 100644 release/src/router/libnss-mdns/src/nss-test.c create mode 100644 release/src/router/libnss-mdns/src/nss.c create mode 100644 release/src/router/libnss-mdns/src/nss.h create mode 100644 release/src/router/libnss-mdns/src/util.c create mode 100644 release/src/router/libnss-mdns/src/util.h create mode 100644 release/src/router/libnss-mdns/tests/check_util.c diff --git a/release/src/router/libnss-mdns/.clang-format b/release/src/router/libnss-mdns/.clang-format new file mode 100644 index 00000000000..15540982f4f --- /dev/null +++ b/release/src/router/libnss-mdns/.clang-format @@ -0,0 +1,4 @@ +BasedOnStyle: LLVM +IndentWidth: 4 +PointerAlignment: Left +SortIncludes: false diff --git a/release/src/router/libnss-mdns/.gitignore b/release/src/router/libnss-mdns/.gitignore new file mode 100644 index 00000000000..2e296e41c45 --- /dev/null +++ b/release/src/router/libnss-mdns/.gitignore @@ -0,0 +1,29 @@ +*~ +*.o +*.la +*.lo +*.log +*.tar.gz +*.trs +.deps +.dirstamp +.libs +Makefile +Makefile.in +/aclocal.m4 +/ar-lib +/autom4te.cache +/avahi-test +/compile +/config.* +/configure +/check_util +/depcomp +/install-sh +/libtool +/ltmain.sh +/m4 +/missing +/nss-test +/stamp-h1 +/test-driver diff --git a/release/src/router/libnss-mdns/ACKNOWLEDGEMENTS.md b/release/src/router/libnss-mdns/ACKNOWLEDGEMENTS.md new file mode 100644 index 00000000000..389418406c1 --- /dev/null +++ b/release/src/router/libnss-mdns/ACKNOWLEDGEMENTS.md @@ -0,0 +1,9 @@ +- SHIROYAMA Takayuki, for patches +- Anand Kumria, for patches +- Bastien Nocera, for patches +- Sjoerd Simons, for patches +- Sean Meiners, for search list support +- Philipp Zabel, for ARM support +- Bruce M Simpson, for porting it to FreeBSD +- Trent Lloyd, for migrating to GitHub +- Google LLC, for patches diff --git a/release/src/router/libnss-mdns/LICENSE b/release/src/router/libnss-mdns/LICENSE new file mode 100644 index 00000000000..2d2d780e601 --- /dev/null +++ b/release/src/router/libnss-mdns/LICENSE @@ -0,0 +1,510 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, 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. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +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 library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/release/src/router/libnss-mdns/Makefile.am b/release/src/router/libnss-mdns/Makefile.am new file mode 100644 index 00000000000..d5a83c1cd77 --- /dev/null +++ b/release/src/router/libnss-mdns/Makefile.am @@ -0,0 +1,136 @@ +# This file is part of nss-mdns. +# +# nss-mdns is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# nss-mdns 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 Lesser General Public +# License along with nss-mdns; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +EXTRA_DIST=bootstrap.sh README.md ACKNOWLEDGEMENTS.md NEWS.md LICENSE +ACLOCAL_AMFLAGS=-I m4 + +# src +EXTRA_DIST += src/map-file + +AM_CFLAGS = \ + -DMDNS_ALLOW_FILE=\"$(MDNS_ALLOW_FILE)\" \ + -DAVAHI_SOCKET=\"$(AVAHI_SOCKET)\" + +AM_LDFLAGS=-avoid-version -module -export-dynamic + +if FREEBSD_NSS +lib_LTLIBRARIES = \ + nss_mdns.la \ + nss_mdns4.la \ + nss_mdns6.la \ + nss_mdns_minimal.la \ + nss_mdns4_minimal.la \ + nss_mdns6_minimal.la +else +lib_LTLIBRARIES = \ + libnss_mdns.la \ + libnss_mdns4.la \ + libnss_mdns6.la \ + libnss_mdns_minimal.la \ + libnss_mdns4_minimal.la \ + libnss_mdns6_minimal.la +endif + + +check_PROGRAMS = nss-test avahi-test + +libnss_mdns_la_SOURCES=src/util.c src/util.h src/avahi.c src/avahi.h src/nss.c src/nss.h +libnss_mdns_la_CFLAGS=$(AM_CFLAGS) +libnss_mdns_la_LDFLAGS=$(AM_LDFLAGS) -shrext .so.2 -Wl,-version-script=$(srcdir)/src/map-file + +libnss_mdns_minimal_la_SOURCES=$(libnss_mdns_la_SOURCES) +libnss_mdns_minimal_la_CFLAGS=$(libnss_mdns_la_CFLAGS) -DMDNS_MINIMAL +libnss_mdns_minimal_la_LDFLAGS=$(libnss_mdns_la_LDFLAGS) + +libnss_mdns4_la_SOURCES=$(libnss_mdns_la_SOURCES) +libnss_mdns4_la_CFLAGS=$(libnss_mdns_la_CFLAGS) -DNSS_IPV4_ONLY=1 +libnss_mdns4_la_LDFLAGS=$(libnss_mdns_la_LDFLAGS) + +libnss_mdns4_minimal_la_SOURCES=$(libnss_mdns_la_SOURCES) +libnss_mdns4_minimal_la_CFLAGS=$(libnss_mdns_la_CFLAGS) -DNSS_IPV4_ONLY=1 -DMDNS_MINIMAL +libnss_mdns4_minimal_la_LDFLAGS=$(libnss_mdns_la_LDFLAGS) + +libnss_mdns6_la_SOURCES=$(libnss_mdns_la_SOURCES) +libnss_mdns6_la_CFLAGS=$(libnss_mdns_la_CFLAGS) -DNSS_IPV6_ONLY=1 +libnss_mdns6_la_LDFLAGS=$(libnss_mdns_la_LDFLAGS) + +libnss_mdns6_minimal_la_SOURCES=$(libnss_mdns_la_SOURCES) +libnss_mdns6_minimal_la_CFLAGS=$(libnss_mdns_la_CFLAGS) -DNSS_IPV6_ONLY=1 -DMDNS_MINIMAL +libnss_mdns6_minimal_la_LDFLAGS=$(libnss_mdns_la_LDFLAGS) + +nss_mdns_la_SOURCES=$(libnss_mdns_la_SOURCES) src/bsdnss.c +nss_mdns_la_CFLAGS=$(AM_CFLAGS) +nss_mdns_la_LDFLAGS=$(AM_LDFLAGS) -shrext .so.1 + +nss_mdns_minimal_la_SOURCES=$(nss_mdns_la_SOURCES) +nss_mdns_minimal_la_CFLAGS=$(nss_mdns_la_CFLAGS) -DMDNS_MINIMAL +nss_mdns_minimal_la_LDFLAGS=$(nss_mdns_la_LDFLAGS) + +nss_mdns4_la_SOURCES=$(nss_mdns_la_SOURCES) +nss_mdns4_la_CFLAGS=$(nss_mdns_la_CFLAGS) -DNSS_IPV4_ONLY=1 +nss_mdns4_la_LDFLAGS=$(nss_mdns_la_LDFLAGS) + +nss_mdns4_minimal_la_SOURCES=$(nss_mdns_la_SOURCES) +nss_mdns4_minimal_la_CFLAGS=$(nss_mdns_la_CFLAGS) -DNSS_IPV4_ONLY=1 -DMDNS_MINIMAL +nss_mdns4_minimal_la_LDFLAGS=$(nss_mdns_la_LDFLAGS) + +nss_mdns6_la_SOURCES=$(nss_mdns_la_SOURCES) +nss_mdns6_la_CFLAGS=$(nss_mdns_la_CFLAGS) -DNSS_IPV6_ONLY=1 +nss_mdns6_la_LDFLAGS=$(nss_mdns_la_LDFLAGS) + +nss_mdns6_minimal_la_SOURCES=$(nss_mdns_la_SOURCES) +nss_mdns6_minimal_la_CFLAGS=$(nss_mdns_la_CFLAGS) -DNSS_IPV6_ONLY=1 -DMDNS_MINIMAL +nss_mdns6_minimal_la_LDFLAGS=$(nss_mdns_la_LDFLAGS) + +avahi_test_SOURCES = \ + src/avahi.c src/avahi.h \ + src/util.c src/util.h \ + src/avahi-test.c + +nss_test_SOURCES = \ + src/nss-test.c + +install-exec-hook: + rm -f $(DESTDIR)$(libdir)/libnss_mdns.la + rm -f $(DESTDIR)$(libdir)/libnss_mdns_minimal.la + rm -f $(DESTDIR)$(libdir)/libnss_mdns4.la + rm -f $(DESTDIR)$(libdir)/libnss_mdns4_minimal.la + rm -f $(DESTDIR)$(libdir)/libnss_mdns6.la + rm -f $(DESTDIR)$(libdir)/libnss_mdns6_minimal.la + rm -f $(DESTDIR)$(libdir)/nss_mdns.la + rm -f $(DESTDIR)$(libdir)/nss_mdns_minimal.la + +uninstall-hook: + rm -f $(DESTDIR)$(libdir)/libnss_mdns.so.2 + rm -f $(DESTDIR)$(libdir)/libnss_mdns_minimal.so.2 + rm -f $(DESTDIR)$(libdir)/libnss_mdns4.so.2 + rm -f $(DESTDIR)$(libdir)/libnss_mdns4_minimal.so.2 + rm -f $(DESTDIR)$(libdir)/libnss_mdns6.so.2 + rm -f $(DESTDIR)$(libdir)/libnss_mdns6_minimal.so.2 + rm -f $(DESTDIR)$(libdir)/nss_mdns.so.2 + rm -f $(DESTDIR)$(libdir)/nss_mdns_minimal.so.2 + + +# tests +if ENABLE_TESTS +TESTS = check_util +check_PROGRAMS += check_util +check_util_SOURCES = tests/check_util.c src/util.h +check_util_CFLAGS = @CHECK_CFLAGS@ +check_util_LDADD = src/util.o @CHECK_LIBS@ +endif + +EXTRA_DIST += tests/check_util.c diff --git a/release/src/router/libnss-mdns/NEWS.md b/release/src/router/libnss-mdns/NEWS.md new file mode 100644 index 00000000000..3f2a605172c --- /dev/null +++ b/release/src/router/libnss-mdns/NEWS.md @@ -0,0 +1,181 @@ +# News + +## Sat Jun 12 2021: + +[Version 0.15.1](https://github.com/lathiat/nss-mdns/releases/tag/v0.15.1) +released. Highlights: + +* This fixes the broken previous release by restoring the missing + `src/nss.h` file. If you are using 0.15, you must upgrade to this + version, or downgrade to a previous one. + +## Mon May 10 2021: + +[Version 0.15](https://github.com/lathiat/nss-mdns/releases/tag/v0.15) +released. Highlights: + +* Updated README.md for clarity +* The return of BSD support! +* Support for `AVAHI_SOCKET` in `/run` (instead of legacy `/var/run`) + +## Sun Mar 18 2018: + +[Version 0.14.1](https://github.com/lathiat/nss-mdns/releases/tag/v0.14.1) +released. Highlights: + +* No code changes +* Fix unit tests to properly work on s390x + +## Sun Mar 18 2018: + +[Version 0.14](https://github.com/lathiat/nss-mdns/releases/tag/v0.14) +released. Highlights: + +* Fix -Wformat-truncation problem during reading of the allow file + +## Tue Feb 20 2018: + +[Version 0.13.2](https://github.com/lathiat/nss-mdns/releases/tag/v0.13.2) +released. Highlights: + +* No code changes +* Change how `./configure --enable/disable-tests` works: + * `--enable-tests`: tests are enabled and will fail if dependencies are + not found + * `--disable-tests`: tests are not enabled and will not be built even + if dependencies are found + * no flag given: tests are conditionally enabled if dependencies are + found + +## Sun Feb 18 2018: + +[Version 0.13.1](https://github.com/lathiat/nss-mdns/releases/tag/v0.13.1) +released. Highlights: + +* Very minor code changes (should result in no binary changes) +* Reformat source to 80 columns +* Improve configure options to allow disabling tests even if + the testing libraries are present +* Automake is now non-recursive +* Hardcoded paths are now exposed as configure variables + +## Mon Feb 12 2018: + +[Version 0.13](https://github.com/lathiat/nss-mdns/releases/tag/v0.13) +released. Highlights: + +* Fix an old memory leak in reverse lookup +* Fix the broken workaround for nscd segfaults (not all clients + would see all results) +* Simplify buffer management +* More unit tests, more cleanups, and fewer gotos + +## Sat Feb 10 2018: + +[Version 0.12](https://github.com/lathiat/nss-mdns/releases/tag/v0.12) +released. Highlights: + +* Fix segfault when using nscd +* Remove untested, unmaintained BSD support (please help out if you + would like BSD support to return!) + +## Mon Jan 22 2018: + +[Version 0.11](https://github.com/lathiat/nss-mdns/releases/tag/v0.11) +released. The first release in some time! Highlights: + +* Moved to new GitHub location, docs migrated to markdown +* The long-deprecated `LEGACY` mode is removed +* The long-deprecated `HONOUR_SEARCH_DOMAINS` option is removed +* Unit tests are now included, with `make check` +* nss-mdns now implements [standard + heuristics](https://support.apple.com/en-us/HT201275) for + detecting `.local` unicast resolution and will automatically + disable resolution when a local server responds to `.local` requests +* `_nss_mdns_gethostbyname3_r` and `_nss_mdns_gethostbyname4_r` + are now implemented +* Full dual-stack IPv4/IPv6 support is implemented + +## Sat May 12 2007: + +[Version 0.10](https://github.com/lathiat/nss-mdns/releases/tag/v0.10) +released. Changes include: Ported to FreeBSD; alignment fixes for SPARC. + +## Mon Jan 1 2007: + +[Version 0.9](https://github.com/lathiat/nss-mdns/releases/tag/v0.9) +released. Changes include: Make most shared library symbols private to +not conflict with any symbols of the program we're loaded into. Fix a +potential endless loop in the mDNS packet parsing code. + +**Please note that due to security reasons from this release on the +minimal mDNS stack included in `nss-mdns` (dubbed "legacy") is no +longer built by default. Thus, `nss-mdns` will not work unless +[Avahi](http://avahi.org/) is running! That makes Avahi essentially a +hard dependency of `nss-mdns`. Pass `--enable-legacy` to reenable the +mini mDNS stack again. Please note as well that this release does not +honour `/etc/resolv.conf` domain search lists by default anymore. It +created a lot of problems and was never recommended anyway. You may +reenable this functionality by passing `--enable-search-domains`.** + +## Sat Apr 29 2006: + +[Version 0.8](https://github.com/lathiat/nss-mdns/releases/tag/v0.8) +released. Changes include: Build time option to disable "legacy unicast" mDNS +requests, i.e. resolve exclusively with Avahi; build a special +`_minimal` flavour of the shared objects to minimize +unnecessary name lookup timeouts; fix IPv6 resolving when using +Avahi. + +**Please note that starting with nss-mdns 0.8 we encourage you to use +a different `/etc/nsswitch.conf` configuration line. See below +for more information!** + +## Sat Nov 19 2005: + +[Version +0.7](https://github.com/lathiat/nss-mdns/releases/tag/v0.7) +released. Changes include: Portability patch for ARM from Philipp +Zabel; make sure not to print any messages to STDERR; deal with OOM +situations properly; if multiple addresses are assigned to the same +interface make sure to send a query packet only once; other cleanups + +## Sun Aug 21 2005: + +[Version 0.6](https://github.com/lathiat/nss-mdns/releases/tag/v0.6) +released. Changes include: honour search list in +`/etc/resolv.conf`; try to contact [Avahi](http://avahi.org/) for +resolving. + +## Sat Jun 4 2005: + +[Version 0.5](https://github.com/lathiat/nss-mdns/releases/tag/v0.5) +released. Changes include: only lookup hostnames ending in +`.local`; add support for a configuration file +(`/etc/mdns.allow`) to allow lookups for other names. + +## Sun May 15 2005: + +[Version 0.4](https://github.com/lathiat/nss-mdns/releases/tag/v0.4) +released. Changes include: small portability fix for big endian +architectures; send "legacy unicast" packets instead of normal mDNS +packets (this should reduce traffic and improve response time) + +## Jan Sun 16 2005: + +[Version +0.3](https://github.com/lathiat/nss-mdns/releases/tag/v0.3) +released. Changes include: add Debianization; use `ip6.arpa` instead +of `ip6.int` for reverse IPv6 lookups. + +## Fri Dec 17 2004: + +[Version 0.2](https://github.com/lathiat/nss-mdns/releases/tag/v0.2) +released. Changes include: send mDNS queries on every interface that +supports multicasts, instead of only the one with the default route, +making `nss-mdns` more robust on multi-homed hosts; gcc 2.95 +compatiblity. + +## Mon Dec 6 2004: + +[Version 0.1](https://github.com/lathiat/nss-mdns/releases/tag/v0.1) diff --git a/release/src/router/libnss-mdns/README.md b/release/src/router/libnss-mdns/README.md new file mode 100644 index 00000000000..5860ed863b4 --- /dev/null +++ b/release/src/router/libnss-mdns/README.md @@ -0,0 +1,221 @@ +# nss-mdns + +*Copyright 2004-2007 Lennart Poettering <mzaffzqaf (at) 0pointer +(dot) de>* + +- [License](#license) +- [Overview](#overview) +- [Current Status](#current-status) +- [Documentation](#documentation) +- [Requirements](#requirements) +- [Installation](#installation) + +## License + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +## Overview + +`nss-mdns` is a plugin for the GNU Name Service Switch (NSS) +functionality of the GNU C Library (`glibc`) providing host name +resolution via [Multicast DNS](http://www.multicastdns.org/) (aka +*Zeroconf*, aka *Apple Rendezvous*, aka *Apple Bonjour*), effectively +allowing name resolution by common Unix/Linux programs in the ad-hoc +mDNS domain `.local`. + +`nss-mdns` provides client functionality only, which +means that you have to run a mDNS responder daemon seperately +from `nss-mdns` if you want to register the local host name via +mDNS. I recommend [Avahi](http://avahi.org/). + +`nss-mdns` is very lightweight (9 KByte stripped binary +`.so` compiled with `-DNDEBUG=1 -Os` on i386, `gcc` +4.0), has no dependencies besides the `glibc` and requires only +minimal configuration. + +`nss-mdns` tries to contact a running +[avahi-daemon](http://avahi.org/) for resolving host names and +addresses and making use of its superior record cacheing. If +Avahi is not available at lookup time, the lookups will fail. + +## Current Status + +It works! + +## Documentation + +### Libraries + +After compiling and installing `nss-mdns` you'll find six +new NSS modules in `/lib`: + +- `libnss_mdns.so.2` +- `libnss_mdns4.so.2` +- `libnss_mdns6.so.2` +- `libnss_mdns_minimal.so.2` +- `libnss_mdns4_minimal.so.2` +- `libnss_mdns6_minimal.so.2` + + +`libnss_mdns.so.2` +resolves both IPv6 and IPv4 addresses, `libnss_mdns4.so.2` only +IPv4 addresses and `libnss_mdns6.so.2` only IPv6 addresses. Due +to the fact that most mDNS responders only register local IPv4 +addresses via mDNS, most people will want to use +`libnss_mdns4.so.2` exclusively. Using +`libnss_mdns.so.2` or `libnss_mdns6.so.2` in such a +situation causes long timeouts when resolving hosts since most modern +Unix/Linux applications check for IPv6 addresses first, followed by a +lookup for IPv4. + +`libnss_mdns{4,6,}_minimal.so` (new in version 0.8) is mostly +identical to the versions without `_minimal`. However, they differ in +one way. The minimal versions will always deny to resolve host names +that don't end in `.local` or addresses that aren't in the range +`169.254.x.x` (the range used by +[IPV4LL/APIPA/RFC3927](http://files.zeroconf.org/rfc3927.txt).) +Combining the `_minimal` and the normal NSS modules allows us to make +mDNS authoritative for Zeroconf host names and addresses (and thus +creating no extra burden on DNS servers with always failing requests) +and use it as fallback for everything else. + +### Activation + +To activate one of the NSS modules you have to edit +`/etc/nsswitch.conf` and add `mdns4` and +`mdns4_minimal` (resp. `mdns`, `mdns6`) to the +line starting with "`hosts:`". On Debian this looks like +this: + +
# /etc/nsswitch.conf
+
+passwd:         compat
+group:          compat
+shadow:         compat
+
+hosts:          files mdns4_minimal [NOTFOUND=return] dns mdns4
+networks:       files
+
+protocols:      db files
+services:       db files
+ethers:         db files
+rpc:            db files
+
+netgroup:       nis
+ +That's it. You should now be able to resolve hosts from the +`.local` domain with all your applications. For a quick check +use `glibc`'s `getent` tool: + +
$ getent hosts foo.local
+192.168.50.4    foo.local
+ +Replace *foo* whith a host name that has been registered with +an mDNS responder. (Don't try to use the tools `host` or +`nslookup` for these tests! They bypass the NSS and thus +`nss-mdns` and issue their DNS queries directly.) + +If you run a firewall, don't forget to allow UDP traffic to the the +mDNS multicast address `224.0.0.251` on port 5353. + +**Please note:** The line above makes `nss-mdns` authoritative for the +`.local` domain, unless your unicast DNS server responds to `SOA` +queries for the top level `local` name, or if the request has more +than two labels. (`X.local` might be resolved with `nss-mdns` but +`X.Y.local` will not be.) `nss-mdns` will check `SOA` before every +request to resolve `.local` names, meaning that neither `nss-mdns` nor +`Avahi` need to be disabled to allow `.local` queries to be served +from unicast DNS. (These two checks are only enabled in minimal mode +or if there is no `/etc/mdns.allow` file. Any domain, with any number +of labels, (including `.local`) will still be served authoritatively +from `nss-mdns` if specified in `/etc/mdns.allow`.) + +### `/etc/mdns.allow` + +`nss-mdns` has a simple configuration file `/etc/mdns.allow` for +enabling name lookups via mDNS in other domains than `.local`. + +> Note: The "minimal" version of `nss-mdns` does not read `/etc/mdns.allow` +> under any circumstances. It behaves as if the file does not exist. + +In the recommended configuration, no `/etc/mdns.allow` file is +present. In this case: + +* If the request does not end with `.local` or `.local.`, it is rejected. + Example: `example.test` is rejected. + +* If the request has more than two labels, it is rejected. Example: + `foo.bar.local` is rejected. **This is the two-label limit heuristic.** + +* If, during a request, the system-configured unicast DNS (specified + in `/etc/resolv.conf`) reports an `SOA` record for the top-level + `local` name, the request is rejected. Example: `host -t SOA local` + returns something other than `Host local not found: + 3(NXDOMAIN)`. **This is the unicast SOA heuristic.** + +* Otherwise, the request is processed. + +If present, the file should contain valid domain suffixes, seperated +by newlines. Empty lines are ignored as are comments starting with +`#`. + +To disable the two heuristics described above, and force all `.local` +domains to be resolved regardless of label count or unicast SOA +records, use this configuration file: + +``` +# /etc/mdns.allow +.local. +.local +``` + +To enable mDNS lookups of all names regardless of the domain suffix +and disabling the two heuristics, add a line consisting of `*` only: + +``` +# /etc/mdns.allow +* +``` + +To complete disable mDNS name lookups, use an empty file: +``` +# /etc/mdns.allow +``` + +Again, remember that changing this file has no effect on the "minimal" +version of `nss-mdns`. + +## Requirements + +Currently, `nss-mdns` is tested on Linux only. A fairly modern `glibc` +installation with development headers (2.0 or newer) is required. Not +suprisingly `nss-mdns` requires a kernel compiled with IPv4 +multicasting support enabled. [Avahi](http://avahi.org/) is a hard +dependency when `nss-mdns` is used, however it is not a build-time +requirement. + +`nss-mdns` was developed and tested on Debian GNU/Linux +"testing" from December 2004, it should work on most other Linux +distributions (and maybe Unix versions) since it uses GNU autoconf and +GNU libtool for source code configuration and shared library +management. + +## Installation + +As this package is made with the GNU autotools you should run +`./configure` inside the distribution directory for configuring +the source tree. After that you should run `make` for +compilation and `make install` (as root) for installation of +`nss-mdns`. diff --git a/release/src/router/libnss-mdns/bootstrap.sh b/release/src/router/libnss-mdns/bootstrap.sh new file mode 100755 index 00000000000..4dd3a308daf --- /dev/null +++ b/release/src/router/libnss-mdns/bootstrap.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +# This file is part of nss-mdns. +# +# nss-mdns is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# nss-mdns 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 Lesser General Public +# License along with nss-mdns; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +autoreconf -i -f -v +./configure --sysconfdir=/etc --localstatedir=/var CFLAGS="-Wall -W -Wextra" "$@" +make clean diff --git a/release/src/router/libnss-mdns/configure.ac b/release/src/router/libnss-mdns/configure.ac new file mode 100644 index 00000000000..8e86326bb99 --- /dev/null +++ b/release/src/router/libnss-mdns/configure.ac @@ -0,0 +1,95 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +# This file is part of nss-mdns. +# +# nss-mdns is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# nss-mdns 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 Lesser General Public +# License along with nss-mdns; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +AC_PREREQ([2.69]) +AC_INIT([nss-mdns],[0.15.1],[https://github.com/lathiat/nss-mdns/issues]) +AC_CONFIG_SRCDIR([src/nss.c]) +AC_CONFIG_HEADERS([config.h]) +AM_INIT_AUTOMAKE([foreign 1.9 -Wall subdir-objects]) +AC_CONFIG_MACRO_DIRS([m4]) + +AC_SUBST(PACKAGE_URL, [https://github.com/lathiat/nss-mdns]) + +AC_PREFIX_DEFAULT([]) + +AC_USE_SYSTEM_EXTENSIONS + +AM_SILENT_RULES([yes]) + +# Conditionally enable unittests. +AC_ARG_ENABLE([tests], + AS_HELP_STRING([--disable-tests], + [disable building tests])) + +AS_IF([test "x$enable_tests" != "xno"], + [PKG_CHECK_MODULES([CHECK], [check >= 0.11], + [have_check=yes], [have_check=no])], + [have_check=no]) + +AS_IF([test "x$have_check" = "xyes"], + [], + [AS_IF([test "x$enable_tests" = "xyes"], + [AC_MSG_ERROR([Cannot enable tests: $CHECK_PKG_ERRORS]) + ]) +]) + +AM_CONDITIONAL([ENABLE_TESTS], [test "x$have_check" = "xyes"]) + +# Options for file locations. +AC_ARG_VAR([AVAHI_SOCKET], + [Full path to the avahi-daemon socket, overriding default]) +AS_IF([test "x$AVAHI_SOCKET" = x], + [AVAHI_SOCKET="${runstatedir}/avahi-daemon/socket"]) + +AC_ARG_VAR([MDNS_ALLOW_FILE], + [Full path to the mdns.allow file, overriding default]) +AS_IF([test "x$MDNS_ALLOW_FILE" = x], + [MDNS_ALLOW_FILE="${sysconfdir}/mdns.allow"]) + +# Checks for programs. +AM_PROG_AR +AC_PROG_CC +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET + +# libtool stuff +AC_DISABLE_STATIC +LT_INIT + +# Checks for header files. +AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h sys/time.h unistd.h nss.h sys/ioctl.h]) + +# Enable C99. +AC_PROG_CC_C99 + +# Checks for library functions. +AC_SEARCH_LIBS([__res_nquery], [resolv]) +AC_CHECK_FUNCS([gethostbyaddr gethostbyname gettimeofday inet_ntoa memset select socket strcspn strdup strerror strncasecmp strcasecmp strspn]) + +# FreeBSD has a slightly different NSS interface +case ${host} in + *-freebsd*) freebsd="yes" ;; +esac + +AM_CONDITIONAL([FREEBSD_NSS], [test "x$freebsd" = "xyes"]) + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/release/src/router/libnss-mdns/src/avahi-test.c b/release/src/router/libnss-mdns/src/avahi-test.c new file mode 100644 index 00000000000..db7484b910a --- /dev/null +++ b/release/src/router/libnss-mdns/src/avahi-test.c @@ -0,0 +1,51 @@ +/* + This file is part of nss-mdns. + + nss-mdns is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + nss-mdns 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 Lesser General Public + License along with nss-mdns; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +#include "avahi.h" + +int main(int argc, char* argv[]) { + query_address_result_t result; + char t[256]; + int r; + + if ((r = avahi_resolve_name(AF_INET, argc >= 2 ? argv[1] : "cocaine.local", + &result)) == 0) + printf("AF_INET: %s\n", + inet_ntop(AF_INET, &(result.address.ipv4), t, sizeof(t))); + else + printf("AF_INET: failed (%i).\n", r); + + if ((r = avahi_resolve_address(AF_INET, &(result.address.ipv4), t, + sizeof(t))) == 0) + printf("REVERSE: %s\n", t); + else + printf("REVERSE: failed (%i).\n", r); + + if ((r = avahi_resolve_name(AF_INET6, argc >= 2 ? argv[1] : "cocaine.local", + &result)) == 0) + printf("AF_INET6: %s\n", + inet_ntop(AF_INET6, &(result.address.ipv6), t, sizeof(t))); + else + printf("AF_INET6: failed (%i).\n", r); + + return 0; +} diff --git a/release/src/router/libnss-mdns/src/avahi.c b/release/src/router/libnss-mdns/src/avahi.c new file mode 100644 index 00000000000..9b472bb0ae8 --- /dev/null +++ b/release/src/router/libnss-mdns/src/avahi.c @@ -0,0 +1,183 @@ +/* + This file is part of nss-mdns. + + nss-mdns is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + nss-mdns 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 Lesser General Public + License along with nss-mdns; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "avahi.h" +#include "util.h" + +#define WHITESPACE " \t" + +static FILE* open_socket(void) { + int fd = -1; + struct sockaddr_un sa; + FILE* f = NULL; + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + goto fail; + + set_cloexec(fd); + + memset(&sa, 0, sizeof(sa)); + sa.sun_family = AF_UNIX; + strncpy(sa.sun_path, AVAHI_SOCKET, sizeof(sa.sun_path) - 1); + sa.sun_path[sizeof(sa.sun_path) - 1] = 0; + + if (connect(fd, (struct sockaddr*)&sa, sizeof(sa)) < 0) + goto fail; + + if (!(f = fdopen(fd, "r+"))) + goto fail; + + return f; + +fail: + if (fd >= 0) + close(fd); + + return NULL; +} + +static avahi_resolve_result_t +avahi_resolve_name_with_socket(FILE* f, int af, const char* name, + query_address_result_t* result) { + char* p; + char ln[256]; + + fprintf(f, "RESOLVE-HOSTNAME%s %s\n", af == AF_INET ? "-IPV4" : "-IPV6", + name); + fflush(f); + + if (!(fgets(ln, sizeof(ln), f))) { + return AVAHI_RESOLVE_RESULT_UNAVAIL; + } + + if (ln[0] != '+') { + return AVAHI_RESOLVE_RESULT_HOST_NOT_FOUND; + } + + result->af = af; + + p = ln + 1; + p += strspn(p, WHITESPACE); + + /* Store interface number */ + result->scopeid = (uint32_t)strtol(p, NULL, 0); + p += strcspn(p, WHITESPACE); + p += strspn(p, WHITESPACE); + + /* Skip protocol */ + p += strcspn(p, WHITESPACE); + p += strspn(p, WHITESPACE); + + /* Skip host name */ + p += strcspn(p, WHITESPACE); + p += strspn(p, WHITESPACE); + + /* Cut off end of line */ + *(p + strcspn(p, "\n\r\t ")) = 0; + + if (inet_pton(af, p, &(result->address)) <= 0) { + return AVAHI_RESOLVE_RESULT_UNAVAIL; + } + + return AVAHI_RESOLVE_RESULT_SUCCESS; +} + +avahi_resolve_result_t avahi_resolve_name(int af, const char* name, + query_address_result_t* result) { + if (af != AF_INET && af != AF_INET6) { + return AVAHI_RESOLVE_RESULT_UNAVAIL; + } + + FILE* f = open_socket(); + if (!f) { + return AVAHI_RESOLVE_RESULT_UNAVAIL; + } + + avahi_resolve_result_t ret = + avahi_resolve_name_with_socket(f, af, name, result); + fclose(f); + return ret; +} + +static avahi_resolve_result_t +avahi_resolve_address_with_socket(FILE* f, int af, const void* data, char* name, + size_t name_len) { + char* p; + char a[256], ln[256]; + + fprintf(f, "RESOLVE-ADDRESS %s\n", inet_ntop(af, data, a, sizeof(a))); + + if (!(fgets(ln, sizeof(ln), f))) { + return AVAHI_RESOLVE_RESULT_UNAVAIL; + } + + if (ln[0] != '+') { + return AVAHI_RESOLVE_RESULT_HOST_NOT_FOUND; + } + + p = ln + 1; + p += strspn(p, WHITESPACE); + + /* Skip interface */ + p += strcspn(p, WHITESPACE); + p += strspn(p, WHITESPACE); + + /* Skip protocol */ + p += strcspn(p, WHITESPACE); + p += strspn(p, WHITESPACE); + + /* Cut off end of line */ + *(p + strcspn(p, "\n\r\t ")) = 0; + + strncpy(name, p, name_len - 1); + name[name_len - 1] = 0; + + // Success. + return AVAHI_RESOLVE_RESULT_SUCCESS; +} + +avahi_resolve_result_t avahi_resolve_address(int af, const void* data, + char* name, size_t name_len) { + if (af != AF_INET && af != AF_INET6) { + return AVAHI_RESOLVE_RESULT_UNAVAIL; + } + + FILE* f = open_socket(); + if (!f) { + return AVAHI_RESOLVE_RESULT_UNAVAIL; + } + + avahi_resolve_result_t ret = + avahi_resolve_address_with_socket(f, af, data, name, name_len); + fclose(f); + return ret; +} diff --git a/release/src/router/libnss-mdns/src/avahi.h b/release/src/router/libnss-mdns/src/avahi.h new file mode 100644 index 00000000000..bc6bea97b88 --- /dev/null +++ b/release/src/router/libnss-mdns/src/avahi.h @@ -0,0 +1,62 @@ +#ifndef fooavahihfoo +#define fooavahihfoo + +/* + This file is part of nss-mdns. + + nss-mdns is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + nss-mdns 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 Lesser General Public + License along with nss-mdns; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +// Maximum number of entries to return. +#define MAX_ENTRIES 16 + +typedef struct { + uint32_t address; +} ipv4_address_t; + +typedef struct { + uint8_t address[16]; +} ipv6_address_t; + +typedef struct { + int af; + union { + ipv4_address_t ipv4; + ipv6_address_t ipv6; + } address; + uint32_t scopeid; +} query_address_result_t; + +typedef struct { + int count; + query_address_result_t result[MAX_ENTRIES]; +} userdata_t; + +typedef enum { + AVAHI_RESOLVE_RESULT_SUCCESS, + AVAHI_RESOLVE_RESULT_HOST_NOT_FOUND, + AVAHI_RESOLVE_RESULT_UNAVAIL +} avahi_resolve_result_t; + +avahi_resolve_result_t avahi_resolve_name(int af, const char* name, + query_address_result_t* result); + +avahi_resolve_result_t avahi_resolve_address(int af, const void* data, + char* name, size_t name_len); + +#endif diff --git a/release/src/router/libnss-mdns/src/bsdnss.c b/release/src/router/libnss-mdns/src/bsdnss.c new file mode 100644 index 00000000000..21b31b9b234 --- /dev/null +++ b/release/src/router/libnss-mdns/src/bsdnss.c @@ -0,0 +1,374 @@ +/* + This file is part of nss-mdns. + + nss-mdns is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + nss-mdns 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 Lesser General Public + License along with nss-mdns; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* Original author: Bruce M. Simpson */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "avahi.h" +#include "config.h" +#include "util.h" +#include "nss.h" + +#ifdef MDNS_MINIMAL +/* + * FreeBSD support prefers Avahi. + */ +#endif + +/* + * To turn on utrace() records, compile with -DDEBUG_UTRACE. + */ +#ifdef DEBUG_UTRACE +#define _NSS_UTRACE(msg) \ + do { \ + static const char __msg[] = msg; \ + (void)utrace(__msg, sizeof(__msg)); \ + } while (0) +#else +#define _NSS_UTRACE(msg) +#endif + +ns_mtab* nss_module_register(const char* source, unsigned int* mtabsize, + nss_module_unregister_fn* unreg); + +typedef enum nss_status (*_bsd_nsstub_fn_t)(const char*, struct hostent*, char*, + size_t, int*, int*); + +static NSS_METHOD_PROTOTYPE(__nss_bsdcompat_getaddrinfo); +static NSS_METHOD_PROTOTYPE(__nss_bsdcompat_gethostbyaddr_r); +static NSS_METHOD_PROTOTYPE(__nss_bsdcompat_gethostbyname2_r); +static NSS_METHOD_PROTOTYPE(__nss_bsdcompat_ghbyaddr); +static NSS_METHOD_PROTOTYPE(__nss_bsdcompat_ghbyname); + +static ns_mtab methods[] = { + /* database, name, method, mdata */ + {NSDB_HOSTS, "getaddrinfo", __nss_bsdcompat_getaddrinfo, NULL}, + {NSDB_HOSTS, "gethostbyaddr_r", __nss_bsdcompat_gethostbyaddr_r, NULL}, + {NSDB_HOSTS, "gethostbyname2_r", __nss_bsdcompat_gethostbyname2_r, NULL}, + {NSDB_HOSTS, "ghbyaddr", __nss_bsdcompat_ghbyaddr, NULL}, + {NSDB_HOSTS, "ghbyname", __nss_bsdcompat_ghbyname, NULL}, +}; + +ns_mtab* nss_module_register(const char* source, unsigned int* mtabsize, + nss_module_unregister_fn* unreg) { + + *mtabsize = sizeof(methods) / sizeof(methods[0]); + *unreg = NULL; + return (methods); +} + +/* + * Calling convention: + * ap: const char *name (optional), struct addrinfo *pai (hints, optional) + * retval: struct addrinfo ** + * + * name must always be specified by libc; pai is allocated + * by libc and must always be specified. + * + * We can malloc() addrinfo instances and hang them off ai->next; + * canonnames may also be malloc()'d. + * libc is responsible for mapping our ns error return to gai_strerror(). + * + * libc calls us only to look up qualified hostnames. We don't need to + * worry about port numbers; libc will call getservbyname() and explore + * the appropriate maps configured in nsswitch.conf(5). + * + * _errno and _h_errno are unused by getaddrinfo(), as it is + * [mostly] OS independent interface implemented by Win32. + */ +static int __nss_bsdcompat_getaddrinfo(void* retval, void* mdata __unused, + va_list ap) { + enum nss_status status; + int _errno = 0; + int _h_errno = 0; + struct addrinfo sentinel = {0}, *curp = &sentinel; + const char* name; + const struct addrinfo* pai; + struct addrinfo** resultp; + userdata_t u; + + _NSS_UTRACE("__nss_bsdcompat_getaddrinfo: called"); + + name = va_arg(ap, const char*); + pai = va_arg(ap, struct addrinfo*); + resultp = (struct addrinfo**)retval; + + if (name == NULL || pai == NULL) { + *resultp = NULL; + return (NS_UNAVAIL); + } + + extern enum nss_status _nss_mdns_gethostbyname_impl( + const char* name, int af, userdata_t* u, int* errnop, int* h_errnop); + + status = _nss_mdns_gethostbyname_impl(name, pai->ai_family, &u, &_errno, + &_h_errno); + status = __nss_compat_result(status, _errno); + if (status != NS_SUCCESS) { + return (status); + } + + for (int i = 0; i < u.count; i++) { + struct addrinfo* ai = (struct addrinfo*)malloc( + sizeof(struct addrinfo) + sizeof(struct sockaddr_storage)); + if (ai == NULL) { + if (sentinel.ai_next != NULL) + freeaddrinfo(sentinel.ai_next); + *resultp = NULL; + return (NS_UNAVAIL); + } + struct sockaddr* psa = (struct sockaddr*)(ai + 1); + + memset(ai, 0, sizeof(struct addrinfo)); + ai->ai_flags = pai->ai_flags; + ai->ai_socktype = pai->ai_socktype; + ai->ai_protocol = pai->ai_protocol; + ai->ai_family = u.result[i].af; + memset(psa, 0, sizeof(struct sockaddr_storage)); + psa->sa_len = ai->ai_addrlen; + psa->sa_family = ai->ai_family; + ai->ai_addr = psa; + switch (ai->ai_family) { + case AF_INET: + ai->ai_addrlen = sizeof(struct sockaddr_in); + memcpy(&((struct sockaddr_in*)psa)->sin_addr, &u.result[i].address, + ai->ai_addrlen); + break; + case AF_INET6: + ai->ai_addrlen = sizeof(struct sockaddr_in6); + memcpy(&((struct sockaddr_in6*)psa)->sin6_addr, + &u.result[i].address, ai->ai_addrlen); + break; + default: + ai->ai_addrlen = sizeof(struct sockaddr_storage); + memcpy(psa->sa_data, &u.result[i].address, ai->ai_addrlen); + } + + curp->ai_next = ai; + curp = ai; + } + + *resultp = sentinel.ai_next; + return (status); +} + +/* + * Calling convention: + * ap: const u_char *uaddr, socklen_t len, int af, struct hostent *hp, + * char *buf, size_t buflen, int ret_errno, int *h_errnop + * retval: should be set to NULL or hp passed in + */ +static int __nss_bsdcompat_gethostbyaddr_r(void* retval, void* mdata __unused, + va_list ap) { + void* addr; + char* buf; + int* h_errnop; + struct hostent* hp; + struct hostent** resultp; + int af; + size_t buflen; + int len; + int ret_errno; + enum nss_status status; + + addr = va_arg(ap, void*); + len = va_arg(ap, socklen_t); + af = va_arg(ap, int); + hp = va_arg(ap, struct hostent*); + buf = va_arg(ap, char*); + buflen = va_arg(ap, size_t); + ret_errno = va_arg(ap, int); + h_errnop = va_arg(ap, int*); + resultp = (struct hostent**)retval; + + *resultp = NULL; + status = _nss_mdns_gethostbyaddr_r(addr, len, af, hp, buf, buflen, + &ret_errno, h_errnop); + + status = __nss_compat_result(status, *h_errnop); + if (status == NS_SUCCESS) + *resultp = hp; + return (status); +} + +/* + * Calling convention: + * ap: const char *name, int af, struct hostent *hp, char *buf, + * size_t buflen, int ret_errno, int *h_errnop + * retval is a struct hostent **result passed in by the libc client, + * which is responsible for allocating storage. + */ +static int __nss_bsdcompat_gethostbyname2_r(void* retval, void* mdata __unused, + va_list ap) { + char* buf; + const char* name; + int* h_errnop; + struct hostent* hp; + struct hostent** resultp; + int af; + size_t buflen; + int ret_errno; + enum nss_status status; + + name = va_arg(ap, char*); + af = va_arg(ap, int); + hp = va_arg(ap, struct hostent*); + buf = va_arg(ap, char*); + buflen = va_arg(ap, size_t); + ret_errno = va_arg(ap, int); + h_errnop = va_arg(ap, int*); + resultp = (struct hostent**)retval; + + *resultp = NULL; + if (hp == NULL) + return (NS_UNAVAIL); + + status = _nss_mdns_gethostbyname2_r(name, af, hp, buf, buflen, &ret_errno, + h_errnop); + + status = __nss_compat_result(status, *h_errnop); + if (status == NS_SUCCESS) + *resultp = hp; + return (status); +} + +/* + * Used by getipnodebyaddr(3). + * + * Calling convention: + * ap: struct in[6]_addr *src, size_t len, int af, int *errp + * retval: pointer to a pointer to an uninitialized struct hostent, + * in which should be returned a single pointer to on-heap storage. + * + * This function is responsible for allocating on-heap storage. + * The caller is responsible for calling freehostent() on the returned + * storage. + */ +static int __nss_bsdcompat_ghbyaddr(void* retval, void* mdata __unused, + va_list ap) { + char* buffer; + void* bufp; + int* errp; + struct hostent* hp; + struct hostent** resultp; + void* src; + int af; + size_t buflen = 1024; + size_t len; + int h_errnop; + enum nss_status status; + + src = va_arg(ap, void*); + len = va_arg(ap, size_t); + af = va_arg(ap, int); + errp = va_arg(ap, int*); + resultp = (struct hostent**)retval; + + _NSS_UTRACE("__nss_bsdcompat_ghbyaddr: called"); + + bufp = malloc((sizeof(struct hostent) + buflen)); + if (bufp == NULL) { + *resultp = NULL; + return (NS_UNAVAIL); + } + hp = (struct hostent*)bufp; + buffer = (char*)(hp + 1); + + status = _nss_mdns_gethostbyaddr_r(src, len, af, hp, buffer, buflen, errp, + &h_errnop); + + status = __nss_compat_result(status, *errp); + if (status != NS_SUCCESS) { + free(bufp); + hp = NULL; + } + *resultp = hp; + return (status); +} + +/* + * Used by getipnodebyname(3). + * + * Calling convention: + * ap: const char *name, int af, int *errp + * retval: pointer to a pointer to an uninitialized struct hostent. + * + * This function is responsible for allocating on-heap storage. + * The caller is responsible for calling freehostent() on the returned + * storage. + */ +static int __nss_bsdcompat_ghbyname(void* retval, void* mdata __unused, + va_list ap) { + char* buffer; + void* bufp; + int* errp; + struct hostent* hp; + struct hostent** resultp; + char* name; + int af; + size_t buflen = 1024; + int h_errnop; + enum nss_status status; + + name = va_arg(ap, char*); + af = va_arg(ap, int); + errp = va_arg(ap, int*); + resultp = (struct hostent**)retval; + + bufp = malloc((sizeof(struct hostent) + buflen)); + if (bufp == NULL) { + *resultp = NULL; + return (NS_UNAVAIL); + } + hp = (struct hostent*)bufp; + buffer = (char*)(hp + 1); + + status = + _nss_mdns_gethostbyname_r(name, hp, buffer, buflen, errp, &h_errnop); + + status = __nss_compat_result(status, *errp); + if (status != NS_SUCCESS) { + free(bufp); + hp = NULL; + } + *resultp = hp; + return (status); +} diff --git a/release/src/router/libnss-mdns/src/map-file b/release/src/router/libnss-mdns/src/map-file new file mode 100644 index 00000000000..69e79879fe7 --- /dev/null +++ b/release/src/router/libnss-mdns/src/map-file @@ -0,0 +1,41 @@ +NSSMDNS_0 { +global: + +_nss_mdns_gethostbyaddr_r; +_nss_mdns4_gethostbyaddr_r; +_nss_mdns6_gethostbyaddr_r; +_nss_mdns_minimal_gethostbyaddr_r; +_nss_mdns4_minimal_gethostbyaddr_r; +_nss_mdns6_minimal_gethostbyaddr_r; + +_nss_mdns_gethostbyname_r; +_nss_mdns4_gethostbyname_r; +_nss_mdns6_gethostbyname_r; +_nss_mdns_minimal_gethostbyname_r; +_nss_mdns4_minimal_gethostbyname_r; +_nss_mdns6_minimal_gethostbyname_r; + +_nss_mdns_gethostbyname2_r; +_nss_mdns4_gethostbyname2_r; +_nss_mdns6_gethostbyname2_r; +_nss_mdns_minimal_gethostbyname2_r; +_nss_mdns4_minimal_gethostbyname2_r; +_nss_mdns6_minimal_gethostbyname2_r; + +_nss_mdns_gethostbyname3_r; +_nss_mdns4_gethostbyname3_r; +_nss_mdns6_gethostbyname3_r; +_nss_mdns_minimal_gethostbyname3_r; +_nss_mdns4_minimal_gethostbyname3_r; +_nss_mdns6_minimal_gethostbyname3_r; + +_nss_mdns_gethostbyname4_r; +_nss_mdns4_gethostbyname4_r; +_nss_mdns6_gethostbyname4_r; +_nss_mdns_minimal_gethostbyname4_r; +_nss_mdns4_minimal_gethostbyname4_r; +_nss_mdns6_minimal_gethostbyname4_r; + +local: +*; +}; diff --git a/release/src/router/libnss-mdns/src/nss-test.c b/release/src/router/libnss-mdns/src/nss-test.c new file mode 100644 index 00000000000..6d2b44a412a --- /dev/null +++ b/release/src/router/libnss-mdns/src/nss-test.c @@ -0,0 +1,145 @@ +/* + This file is part of nss-mdns. + + nss-mdns is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + nss-mdns 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 Lesser General Public + License along with nss-mdns; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#ifdef __FreeBSD__ +#include +#endif + +static int gai(const char* node) { + struct addrinfo hints; + struct addrinfo *result, *rp; + + char str[INET_ADDRSTRLEN]; + char str6[INET6_ADDRSTRLEN]; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_CANONNAME; + hints.ai_socktype = SOCK_STREAM; + + fprintf(stderr, "* doing node lookup with getaddrinfo...\n"); + + int s = getaddrinfo(node, NULL, &hints, &result); + if (s != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); + return 1; + } + int i = 0; + for (rp = result; rp != NULL; rp = rp->ai_next) { + if (rp->ai_canonname) { + fprintf(stderr, "[%d] official name: %s\n", i, rp->ai_canonname); + } + switch (rp->ai_family) { + case AF_INET: + inet_ntop(AF_INET, &((struct sockaddr_in*)rp->ai_addr)->sin_addr, + str, sizeof(str)); + fprintf(stderr, "[%d] addr type: inet\n[%d] address: %s\n", i, i, + str); + break; + case AF_INET6: + inet_ntop(AF_INET6, &((struct sockaddr_in6*)rp->ai_addr)->sin6_addr, + str6, sizeof(str6)); + int scope_id = ((struct sockaddr_in6*)rp->ai_addr)->sin6_scope_id; + if (scope_id) { + fprintf(stderr, "[%d] addr type: inet6\n[%d] address: %s%%%d\n", + i, i, str6, scope_id); + } else { + fprintf(stderr, "[%d] addr type: inet6\n[%d] address: %s\n", i, + i, str6); + } + break; + } + fprintf(stderr, "\n"); + i++; + } + freeaddrinfo(result); + + return 0; +} + +static int gethostbyX(const char* node) { + struct hostent* he; + in_addr_t** a; + uint8_t t[256]; + + if (inet_pton(AF_INET, node, &t) > 0) { + fprintf(stderr, "* doing ipv4 lookup with gethostbyaddr...\n"); + he = gethostbyaddr(t, 4, AF_INET); + } else if (inet_pton(AF_INET6, node, &t) > 0) { + fprintf(stderr, "* doing ipv6 lookup with gethostbyaddr...\n"); + he = gethostbyaddr(t, 16, AF_INET6); + } else { + fprintf(stderr, "* doing name lookup with gethostbyname...\n"); + he = gethostbyname(node); + } + + if (!he) { + fprintf(stderr, "lookup failed\n"); + return 1; + } + + fprintf(stderr, "official name: %s\n", he->h_name); + + if (!he->h_aliases || !he->h_aliases[0]) + fprintf(stderr, "no aliases\n"); + else { + char** h; + fprintf(stderr, "aliases:"); + for (h = he->h_aliases; *h; h++) + fprintf(stderr, " %s", *h); + fprintf(stderr, "\n"); + } + + fprintf(stderr, "addr type: %s\n", + he->h_addrtype == AF_INET + ? "inet" + : (he->h_addrtype == AF_INET6 ? "inet6" : NULL)); + fprintf(stderr, "addr length: %i\n", he->h_length); + + fprintf(stderr, "addresses:"); + for (a = (in_addr_t**)he->h_addr_list; *a; a++) { + char txt[256]; + fprintf(stderr, " %s", inet_ntop(he->h_addrtype, *a, txt, sizeof(txt))); + } + fprintf(stderr, "\n"); + + return 0; +} + +int main(int argc, char* argv[]) { + if (argc != 2) { + fprintf(stderr, + "Requires 1 argument: either a host or numeric address\n"); + return 1; + } + const char* node = argv[1]; + gethostbyX(node); + fprintf(stderr, "\n\n"); + gai(node); + return 0; +} diff --git a/release/src/router/libnss-mdns/src/nss.c b/release/src/router/libnss-mdns/src/nss.c new file mode 100644 index 00000000000..2e1a90b5986 --- /dev/null +++ b/release/src/router/libnss-mdns/src/nss.c @@ -0,0 +1,284 @@ +/* + This file is part of nss-mdns. + + nss-mdns is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + nss-mdns is distributed in the hope that it will be useful, but1 + 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 Lesser General Public + License along with nss-mdns; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "avahi.h" +#include "util.h" +#include "nss.h" + +static avahi_resolve_result_t do_avahi_resolve_name(int af, const char* name, + userdata_t* userdata) { + bool ipv4_found = false; + bool ipv6_found = false; + + if (af == AF_INET || af == AF_UNSPEC) { + query_address_result_t address_result; + switch (avahi_resolve_name(AF_INET, name, &address_result)) { + case AVAHI_RESOLVE_RESULT_SUCCESS: + append_address_to_userdata(&address_result, userdata); + ipv4_found = true; + break; + + case AVAHI_RESOLVE_RESULT_HOST_NOT_FOUND: + break; + + case AVAHI_RESOLVE_RESULT_UNAVAIL: + // Something went wrong, just fail. + return AVAHI_RESOLVE_RESULT_UNAVAIL; + } + } + + if (af == AF_INET6 || af == AF_UNSPEC) { + query_address_result_t address_result; + switch (avahi_resolve_name(AF_INET6, name, &address_result)) { + case AVAHI_RESOLVE_RESULT_SUCCESS: + append_address_to_userdata(&address_result, userdata); + ipv6_found = true; + break; + + case AVAHI_RESOLVE_RESULT_HOST_NOT_FOUND: + break; + + case AVAHI_RESOLVE_RESULT_UNAVAIL: + // Something went wrong, just fail. + return AVAHI_RESOLVE_RESULT_UNAVAIL; + } + } + + if (ipv4_found || ipv6_found) { + return AVAHI_RESOLVE_RESULT_SUCCESS; + } else { + return AVAHI_RESOLVE_RESULT_HOST_NOT_FOUND; + } +} + +enum nss_status _nss_mdns_gethostbyname_impl(const char* name, int af, + userdata_t* u, int* errnop, + int* h_errnop) { + + FILE* mdns_allow_file = NULL; + use_name_result_t result; + +#ifdef NSS_IPV4_ONLY + if (af == AF_UNSPEC) { + af = AF_INET; + } +#endif + +#ifdef NSS_IPV6_ONLY + if (af == AF_UNSPEC) { + af = AF_INET6; + } +#endif + +#ifdef NSS_IPV4_ONLY + if (af != AF_INET) +#elif NSS_IPV6_ONLY + if (af != AF_INET6) +#else + if (af != AF_INET && af != AF_INET6 && af != AF_UNSPEC) +#endif + { + *errnop = EINVAL; + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } + + u->count = 0; + +#ifndef MDNS_MINIMAL + mdns_allow_file = fopen(MDNS_ALLOW_FILE, "r"); +#endif + result = verify_name_allowed_with_soa(name, mdns_allow_file, + TEST_LOCAL_SOA_AUTO); +#ifndef MDNS_MINIMAL + if (mdns_allow_file) + fclose(mdns_allow_file); +#endif + + if (result == USE_NAME_RESULT_SKIP) { + *errnop = EINVAL; + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } + + switch (do_avahi_resolve_name(af, name, u)) { + case AVAHI_RESOLVE_RESULT_SUCCESS: + return NSS_STATUS_SUCCESS; + + case AVAHI_RESOLVE_RESULT_HOST_NOT_FOUND: + *errnop = ETIMEDOUT; + *h_errnop = HOST_NOT_FOUND; + if (result == USE_NAME_RESULT_OPTIONAL) { + /* continue to dns plugin if DNS .local zone is detected. */ + *h_errnop = TRY_AGAIN; + return NSS_STATUS_UNAVAIL; + } + return NSS_STATUS_NOTFOUND; + + case AVAHI_RESOLVE_RESULT_UNAVAIL: + default: + *errnop = ETIMEDOUT; + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } +} + +#ifndef __FreeBSD__ +enum nss_status _nss_mdns_gethostbyname4_r(const char* name, + struct gaih_addrtuple** pat, + char* buffer, size_t buflen, + int* errnop, int* h_errnop, + int32_t* ttlp) { + + (void)ttlp; + + userdata_t u; + buffer_t buf; + + enum nss_status status = + _nss_mdns_gethostbyname_impl(name, AF_UNSPEC, &u, errnop, h_errnop); + if (status != NSS_STATUS_SUCCESS) { + return status; + } + buffer_init(&buf, buffer, buflen); + return convert_userdata_to_addrtuple(&u, name, pat, &buf, errnop, h_errnop); +} +#endif + +enum nss_status _nss_mdns_gethostbyname3_r(const char* name, int af, + struct hostent* result, char* buffer, + size_t buflen, int* errnop, + int* h_errnop, int32_t* ttlp, + char** canonp) { + + (void)ttlp; + (void)canonp; + + buffer_t buf; + userdata_t u; + + // The interfaces for gethostbyname3_r and below do not actually support + // returning results for more than one address family + if (af == AF_UNSPEC) { +#ifdef NSS_IPV6_ONLY + af = AF_INET6; +#else + af = AF_INET; +#endif + } + + enum nss_status status = _nss_mdns_gethostbyname_impl(name, af, &u, errnop, h_errnop); + if (status != NSS_STATUS_SUCCESS) { + return status; + } + buffer_init(&buf, buffer, buflen); + return convert_userdata_for_name_to_hostent(&u, name, af, result, &buf, + errnop, h_errnop); +} + +enum nss_status _nss_mdns_gethostbyname2_r(const char* name, int af, + struct hostent* result, char* buffer, + size_t buflen, int* errnop, + int* h_errnop) { + + return _nss_mdns_gethostbyname3_r(name, af, result, buffer, buflen, errnop, + h_errnop, NULL, NULL); +} + +enum nss_status _nss_mdns_gethostbyname_r(const char* name, + struct hostent* result, char* buffer, + size_t buflen, int* errnop, + int* h_errnop) { + + return _nss_mdns_gethostbyname2_r(name, AF_UNSPEC, result, buffer, buflen, + errnop, h_errnop); +} + +enum nss_status _nss_mdns_gethostbyaddr_r(const void* addr, int len, int af, + struct hostent* result, char* buffer, + size_t buflen, int* errnop, + int* h_errnop) { + + size_t address_length; + char t[256]; + + /* Check for address types */ + address_length = + af == AF_INET ? sizeof(ipv4_address_t) : sizeof(ipv6_address_t); + + if (len < (int)address_length || +#ifdef NSS_IPV4_ONLY + af != AF_INET +#elif NSS_IPV6_ONLY + af != AF_INET6 +#else + (af != AF_INET && af != AF_INET6) +#endif + ) { + *errnop = EINVAL; + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } + +#ifdef MDNS_MINIMAL + /* Only query for 169.254.0.0/16 IPv4 in minimal mode */ + if ((af == AF_INET && + ((ntohl(*(const uint32_t*)addr) & 0xFFFF0000UL) != 0xA9FE0000UL)) || + (af == AF_INET6 && !(((const uint8_t*)addr)[0] == 0xFE && + (((const uint8_t*)addr)[1] >> 6) == 2))) { + *errnop = EINVAL; + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } +#endif + + /* Lookup using Avahi */ + buffer_t buf; + switch (avahi_resolve_address(af, addr, t, sizeof(t))) { + case AVAHI_RESOLVE_RESULT_SUCCESS: + buffer_init(&buf, buffer, buflen); + return convert_name_and_addr_to_hostent(t, addr, address_length, af, + result, &buf, errnop, h_errnop); + + case AVAHI_RESOLVE_RESULT_HOST_NOT_FOUND: + *errnop = ETIMEDOUT; + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + + case AVAHI_RESOLVE_RESULT_UNAVAIL: + default: + *errnop = ETIMEDOUT; + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } +} diff --git a/release/src/router/libnss-mdns/src/nss.h b/release/src/router/libnss-mdns/src/nss.h new file mode 100644 index 00000000000..dd8dbff0fff --- /dev/null +++ b/release/src/router/libnss-mdns/src/nss.h @@ -0,0 +1,52 @@ +#ifndef src_nss_h +#define src_nss_h + +#if defined(NSS_IPV4_ONLY) && !defined(MDNS_MINIMAL) +#define _nss_mdns_gethostbyname4_r _nss_mdns4_gethostbyname4_r +#define _nss_mdns_gethostbyname3_r _nss_mdns4_gethostbyname3_r +#define _nss_mdns_gethostbyname2_r _nss_mdns4_gethostbyname2_r +#define _nss_mdns_gethostbyname_r _nss_mdns4_gethostbyname_r +#define _nss_mdns_gethostbyaddr_r _nss_mdns4_gethostbyaddr_r +#elif defined(NSS_IPV4_ONLY) && defined(MDNS_MINIMAL) +#define _nss_mdns_gethostbyname4_r _nss_mdns4_minimal_gethostbyname4_r +#define _nss_mdns_gethostbyname3_r _nss_mdns4_minimal_gethostbyname3_r +#define _nss_mdns_gethostbyname2_r _nss_mdns4_minimal_gethostbyname2_r +#define _nss_mdns_gethostbyname_r _nss_mdns4_minimal_gethostbyname_r +#define _nss_mdns_gethostbyaddr_r _nss_mdns4_minimal_gethostbyaddr_r +#elif defined(NSS_IPV6_ONLY) && !defined(MDNS_MINIMAL) +#define _nss_mdns_gethostbyname4_r _nss_mdns6_gethostbyname4_r +#define _nss_mdns_gethostbyname3_r _nss_mdns6_gethostbyname3_r +#define _nss_mdns_gethostbyname2_r _nss_mdns6_gethostbyname2_r +#define _nss_mdns_gethostbyname_r _nss_mdns6_gethostbyname_r +#define _nss_mdns_gethostbyaddr_r _nss_mdns6_gethostbyaddr_r +#elif defined(NSS_IPV6_ONLY) && defined(MDNS_MINIMAL) +#define _nss_mdns_gethostbyname4_r _nss_mdns6_minimal_gethostbyname4_r +#define _nss_mdns_gethostbyname3_r _nss_mdns6_minimal_gethostbyname3_r +#define _nss_mdns_gethostbyname2_r _nss_mdns6_minimal_gethostbyname2_r +#define _nss_mdns_gethostbyname_r _nss_mdns6_minimal_gethostbyname_r +#define _nss_mdns_gethostbyaddr_r _nss_mdns6_minimal_gethostbyaddr_r +#elif defined(MDNS_MINIMAL) +#define _nss_mdns_gethostbyname4_r _nss_mdns_minimal_gethostbyname4_r +#define _nss_mdns_gethostbyname3_r _nss_mdns_minimal_gethostbyname3_r +#define _nss_mdns_gethostbyname2_r _nss_mdns_minimal_gethostbyname2_r +#define _nss_mdns_gethostbyname_r _nss_mdns_minimal_gethostbyname_r +#define _nss_mdns_gethostbyaddr_r _nss_mdns_minimal_gethostbyaddr_r +#endif + +// Define prototypes for nss function we're going to export (fixes GCC warnings) +#ifndef __FreeBSD__ +enum nss_status _nss_mdns_gethostbyname4_r(const char*, struct gaih_addrtuple**, + char*, size_t, int*, int*, int32_t*); +#endif +enum nss_status _nss_mdns_gethostbyname3_r(const char*, int, struct hostent*, + char*, size_t, int*, int*, int32_t*, + char**); +enum nss_status _nss_mdns_gethostbyname2_r(const char*, int, struct hostent*, + char*, size_t, int*, int*); +enum nss_status _nss_mdns_gethostbyname_r(const char*, struct hostent*, char*, + size_t, int*, int*); +enum nss_status _nss_mdns_gethostbyaddr_r(const void*, int, int, + struct hostent*, char*, size_t, int*, + int*); + +#endif diff --git a/release/src/router/libnss-mdns/src/util.c b/release/src/router/libnss-mdns/src/util.c new file mode 100644 index 00000000000..0a1c28a5a28 --- /dev/null +++ b/release/src/router/libnss-mdns/src/util.c @@ -0,0 +1,336 @@ +/* + This file is part of nss-mdns. + + nss-mdns is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + nss-mdns 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 Lesser General Public + License along with nss-mdns; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" + +int set_cloexec(int fd) { + int n; + assert(fd >= 0); + + if ((n = fcntl(fd, F_GETFD)) < 0) + return -1; + + if (n & FD_CLOEXEC) + return 0; + + return fcntl(fd, F_SETFD, n | FD_CLOEXEC); +} + +int ends_with(const char* name, const char* suffix) { + size_t ln, ls; + assert(name); + assert(suffix); + + if ((ls = strlen(suffix)) > (ln = strlen(name))) + return 0; + + return strcasecmp(name + ln - ls, suffix) == 0; +} + +use_name_result_t verify_name_allowed_with_soa(const char* name, + FILE* mdns_allow_file, + test_local_soa_t test) { + switch (verify_name_allowed(name, mdns_allow_file)) { + case VERIFY_NAME_RESULT_NOT_ALLOWED: + return USE_NAME_RESULT_SKIP; + case VERIFY_NAME_RESULT_ALLOWED: + return USE_NAME_RESULT_AUTHORITATIVE; + case VERIFY_NAME_RESULT_ALLOWED_IF_NO_LOCAL_SOA: + if (test == TEST_LOCAL_SOA_YES || + (test == TEST_LOCAL_SOA_AUTO && local_soa()) ) + /* Make multicast resolution not authoritative for .local zone. + * Allow continuing to unicast resolution after multicast had not worked. */ + return USE_NAME_RESULT_OPTIONAL; + else + return USE_NAME_RESULT_AUTHORITATIVE; + default: + return USE_NAME_RESULT_SKIP; + } +} + +verify_name_result_t verify_name_allowed(const char* name, + FILE* mdns_allow_file) { + assert(name); + + if (mdns_allow_file) { + int valid = 0; + + while (!feof(mdns_allow_file)) { + char ln[128], ln2[129], *t; + + if (!fgets(ln, sizeof(ln), mdns_allow_file)) + break; + + ln[strcspn(ln, "#\t\n\r ")] = 0; + + if (ln[0] == 0) + continue; + + if (strcmp(ln, "*") == 0) { + valid = 1; + break; + } + + if (ln[0] != '.') + snprintf(t = ln2, sizeof(ln2), ".%s", ln); + else + t = ln; + + if (ends_with(name, t)) { + valid = 1; + break; + } + } + if (valid) + return VERIFY_NAME_RESULT_ALLOWED; + else + return VERIFY_NAME_RESULT_NOT_ALLOWED; + } else { + if ((ends_with(name, ".local") || ends_with(name, ".local.")) && + (label_count(name) == 2)) + return VERIFY_NAME_RESULT_ALLOWED_IF_NO_LOCAL_SOA; + else + return VERIFY_NAME_RESULT_NOT_ALLOWED; + } +} + +int local_soa(void) { + /* FreeBSD requires the state to be zeroed before calling res_ninit() */ + struct __res_state state = { + 0, + }; + int result; + unsigned char answer[NS_MAXMSG]; + + result = res_ninit(&state); + if (result == -1) + return 0; + result = + res_nquery(&state, "local", ns_c_in, ns_t_soa, answer, sizeof answer); + res_nclose(&state); + return result > 0; +} + +int label_count(const char* name) { + // Start with single label. + int count = 1; + size_t i, len; + assert(name); + + len = strlen(name); + // Count all dots not in the last place. + for (i = 0; i < len; i++) { + if ((name[i] == '.') && (i != (len - 1))) + count++; + } + + return count; +} + +enum nss_status convert_name_and_addr_to_hostent(const char* name, + const void* addr, int len, + int af, struct hostent* result, + buffer_t* buf, int* errnop, + int* h_errnop) { + // Set empty list of aliases. + result->h_aliases = (char**)buffer_alloc(buf, sizeof(char**)); + RETURN_IF_FAILED_ALLOC(result->h_aliases); + + // Set official name. + result->h_name = buffer_strdup(buf, name); + RETURN_IF_FAILED_ALLOC(result->h_name); + + // Set addrtype and length. + result->h_addrtype = af; + result->h_length = len; + + // Initialize address list of length 1, NULL terminated. + result->h_addr_list = buffer_alloc(buf, 2 * sizeof(char**)); + RETURN_IF_FAILED_ALLOC(result->h_addr_list); + + // Copy the address. + result->h_addr_list[0] = buffer_alloc(buf, len); + RETURN_IF_FAILED_ALLOC(result->h_addr_list[0]); + memcpy(result->h_addr_list[0], addr, len); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status convert_userdata_for_name_to_hostent(const userdata_t* u, + const char* name, int af, + struct hostent* result, + buffer_t* buf, int* errnop, + int* h_errnop) { + size_t address_length = + af == AF_INET ? sizeof(ipv4_address_t) : sizeof(ipv6_address_t); + + // Set empty list of aliases. + result->h_aliases = (char**)buffer_alloc(buf, sizeof(char**)); + RETURN_IF_FAILED_ALLOC(result->h_aliases); + + // Set official name. + result->h_name = buffer_strdup(buf, name); + RETURN_IF_FAILED_ALLOC(result->h_name); + + // Set addrtype and length. + result->h_addrtype = af; + result->h_length = address_length; + + // Initialize address list, NULL terminated. + result->h_addr_list = buffer_alloc(buf, (u->count + 1) * sizeof(char**)); + RETURN_IF_FAILED_ALLOC(result->h_addr_list); + + // Copy the addresses. + for (int i = 0; i < u->count; i++) { + char* addr = buffer_alloc(buf, address_length); + RETURN_IF_FAILED_ALLOC(addr); + memcpy(addr, &u->result[i].address, address_length); + result->h_addr_list[i] = addr; + } + + return NSS_STATUS_SUCCESS; +} + +#ifndef __FreeBSD__ +enum nss_status convert_userdata_to_addrtuple(const userdata_t* u, + const char* name, + struct gaih_addrtuple** pat, + buffer_t* buf, int* errnop, + int* h_errnop) { + + // Copy name to buffer (referenced in every result address tuple). + char* buffer_name = buffer_strdup(buf, name); + RETURN_IF_FAILED_ALLOC(buffer_name); + + struct gaih_addrtuple* tuple_prev = NULL; + for (int i = 0; i < u->count; i++) { + const query_address_result_t* result = &u->result[i]; + struct gaih_addrtuple* tuple; + if (tuple_prev == NULL && *pat) { + // The caller has provided a valid initial location in *pat, + // so use that as the first result. Without this, nscd will + // segfault because it assumes that the buffer is only used as + // an overflow. + // See + // https://lists.freedesktop.org/archives/systemd-devel/2013-February/008606.html + tuple = *pat; + memset(tuple, 0, sizeof(*tuple)); + } else { + // Allocate a new tuple from the buffer. + tuple = buffer_alloc(buf, sizeof(struct gaih_addrtuple)); + RETURN_IF_FAILED_ALLOC(tuple); + } + + size_t address_length = result->af == AF_INET ? sizeof(ipv4_address_t) + : sizeof(ipv6_address_t); + + // Assign the (always same) name. + tuple->name = buffer_name; + + // Assign actual address family of address. + tuple->family = result->af; + + // Copy address. + memcpy(&(tuple->addr), &(result->address), address_length); + + // Assign interface scope id + tuple->scopeid = result->scopeid; + + if (tuple_prev == NULL) { + // This is the first tuple. + // Return the start of the list in *pat. + *pat = tuple; + } else { + // Link the new tuple into the previous tuple. + tuple_prev->next = tuple; + } + + tuple_prev = tuple; + } + + return NSS_STATUS_SUCCESS; +} +#endif + +static char* aligned_ptr(char* p) { + uintptr_t ptr = (uintptr_t)p; + if (ptr % sizeof(void*)) { + p += sizeof(void*) - (ptr % sizeof(void*)); + } + return p; +} + +void buffer_init(buffer_t* buf, char* buffer, size_t buflen) { + // next always points to an aligned location. + buf->next = aligned_ptr(buffer); + // end is one past the buffer. + buf->end = buffer + buflen; +} + +void* buffer_alloc(buffer_t* buf, size_t size) { + // Zero-length allocations always succeed with non-NULL. + if (size == 0) { + return buf; // Just a convenient non-NULL pointer. + } + + char* alloc_end = buf->next + size; + if (alloc_end > buf->end) { + // No more memory in the buffer. + return NULL; + } + + // We have enough space. Set up the next aligned pointer and return + // the current one, zeroed. + char* current = buf->next; + buf->next = aligned_ptr(alloc_end); + memset(current, 0, size); + return current; +} + +char* buffer_strdup(buffer_t* buf, const char* str) { + char* result = buffer_alloc(buf, strlen(str) + 1); + if (result == NULL) { + return NULL; + } + strcpy(result, str); + return result; +} + +void append_address_to_userdata(const query_address_result_t* result, + userdata_t* u) { + assert(result && u); + + if (u->count >= MAX_ENTRIES) + return; + + memcpy(&(u->result[u->count]), result, sizeof(*result)); + u->count++; +} diff --git a/release/src/router/libnss-mdns/src/util.h b/release/src/router/libnss-mdns/src/util.h new file mode 100644 index 00000000000..80527e38f96 --- /dev/null +++ b/release/src/router/libnss-mdns/src/util.h @@ -0,0 +1,137 @@ +#ifndef fooutilhfoo +#define fooutilhfoo + +/* + This file is part of nss-mdns. + + nss-mdns is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + nss-mdns 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 Lesser General Public + License along with nss-mdns; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#include +#include +#ifdef __FreeBSD__ +#include +#endif +#include + +#include "avahi.h" + +// Simple buffer allocator. +typedef struct { + char* next; + char* end; +} buffer_t; + +// Sets up a buffer. +void buffer_init(buffer_t* buf, char* buffer, size_t buflen); + +// Allocates a zeroed, aligned chunk of memory of a given size from the buffer +// manager. +// If there is insufficient space, returns NULL. +void* buffer_alloc(buffer_t* buf, size_t size); + +// Duplicates a string into a newly allocated chunk of memory. +// If there is insufficient space, returns NULL. +char* buffer_strdup(buffer_t* buf, const char* str); + +// Macro to help with checking buffer allocation results. +#define RETURN_IF_FAILED_ALLOC(ptr) \ + if (ptr == NULL) { \ + *errnop = ERANGE; \ + *h_errnop = NO_RECOVERY; \ + return NSS_STATUS_TRYAGAIN; \ + } + +int set_cloexec(int fd); +int ends_with(const char* name, const char* suffix); + +typedef enum { + USE_NAME_RESULT_SKIP, + USE_NAME_RESULT_AUTHORITATIVE, + USE_NAME_RESULT_OPTIONAL, +} use_name_result_t; + +typedef enum { + TEST_LOCAL_SOA_NO, + TEST_LOCAL_SOA_YES, + TEST_LOCAL_SOA_AUTO, +} test_local_soa_t; + +// Returns true if we should try to resolve the name with mDNS. +// +// If mdns_allow_file is NULL, then this implements the "local" SOA +// check and two-label name checks similarly to the algorithm +// described at https://support.apple.com/en-us/HT201275. This means +// that if a unicast DNS server claims authority on "local", or if the +// user tries to resolve a >2-label name, we will not do mDNS resolution. +// +// The two heuristics described above are disabled if mdns_allow_file +// is not NULL. +use_name_result_t verify_name_allowed_with_soa(const char* name, + FILE* mdns_allow_file, + test_local_soa_t test); + +typedef enum { + VERIFY_NAME_RESULT_NOT_ALLOWED, + VERIFY_NAME_RESULT_ALLOWED_IF_NO_LOCAL_SOA, + VERIFY_NAME_RESULT_ALLOWED +} verify_name_result_t; + +// Tells us if the name is not allowed unconditionally, allowed only +// if local_soa() returns false, or unconditionally allowed. +verify_name_result_t verify_name_allowed(const char* name, + FILE* mdns_allow_file); + +// Returns true if a DNS server claims authority over "local". +int local_soa(void); + +// Returns the number of labels in a name. +int label_count(const char* name); + +// Converts from a name and addr into the hostent format, used by +// gethostbyaddr_r. +enum nss_status convert_name_and_addr_to_hostent(const char* name, + const void* addr, int len, + int af, struct hostent* result, + buffer_t* buf, int* errnop, + int* h_errnop); + +// Converts from the userdata struct into the hostent format, used by +// gethostbyaddr3_r. +enum nss_status convert_userdata_for_name_to_hostent(const userdata_t* u, + const char* name, int af, + struct hostent* result, + buffer_t* buf, int* errnop, + int* h_errnop); + +// Converts from the userdata struct into the gaih_addrtuple format, used by +// gethostbyaddr4_r. +#ifndef __FreeBSD__ +enum nss_status convert_userdata_to_addrtuple(const userdata_t* u, + const char* name, + struct gaih_addrtuple** pat, + buffer_t* buf, int* errnop, + int* h_errnop); +#endif + +// Appends a query_address_result to userdata. +void append_address_to_userdata(const query_address_result_t* result, + userdata_t* u); + +#endif diff --git a/release/src/router/libnss-mdns/tests/check_util.c b/release/src/router/libnss-mdns/tests/check_util.c new file mode 100644 index 00000000000..36f1008c0af --- /dev/null +++ b/release/src/router/libnss-mdns/tests/check_util.c @@ -0,0 +1,1060 @@ +/* + This file is part of nss-mdns. + + nss-mdns is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + nss-mdns 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 Lesser General Public + License along with nss-mdns; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#define _DEFAULT_SOURCE + +#include +#include +#include +#include +#include +#include "../src/util.h" + +// Tests that verify_name_allowed works in MINIMAL mode, or with no config file. +// Only names with TLD "local" are allowed. +// Only 2-label names are allowed. +// SOA check is required. +START_TEST(test_verify_name_allowed_minimal) { + ck_assert_int_eq(verify_name_allowed("example.local", NULL), + VERIFY_NAME_RESULT_ALLOWED_IF_NO_LOCAL_SOA); + ck_assert_int_eq(verify_name_allowed("example.local.", NULL), + VERIFY_NAME_RESULT_ALLOWED_IF_NO_LOCAL_SOA); + ck_assert_int_eq(verify_name_allowed("com.example.local", NULL), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq(verify_name_allowed("com.example.local.", NULL), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq(verify_name_allowed("example.com", NULL), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq(verify_name_allowed("example.com.", NULL), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq(verify_name_allowed("example.local.com", NULL), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq(verify_name_allowed("example.local.com.", NULL), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq(verify_name_allowed("", NULL), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq(verify_name_allowed(".", NULL), + VERIFY_NAME_RESULT_NOT_ALLOWED); + + ck_assert_int_eq(verify_name_allowed_with_soa(".", NULL, TEST_LOCAL_SOA_YES), + USE_NAME_RESULT_SKIP); + ck_assert_int_eq(verify_name_allowed_with_soa(".", NULL, TEST_LOCAL_SOA_NO), + USE_NAME_RESULT_SKIP); + ck_assert_int_eq(verify_name_allowed_with_soa(".", NULL, TEST_LOCAL_SOA_AUTO), + USE_NAME_RESULT_SKIP); + ck_assert_int_eq(verify_name_allowed_with_soa("example3.sub.local", + NULL, TEST_LOCAL_SOA_YES), USE_NAME_RESULT_SKIP); + ck_assert_int_eq(verify_name_allowed_with_soa("example4.sub.local", + NULL, TEST_LOCAL_SOA_NO), USE_NAME_RESULT_SKIP); + ck_assert_int_eq(verify_name_allowed_with_soa("example4.sub.local", + NULL, TEST_LOCAL_SOA_AUTO), USE_NAME_RESULT_SKIP); + ck_assert_int_eq(verify_name_allowed_with_soa("example1.local", + NULL, TEST_LOCAL_SOA_YES), USE_NAME_RESULT_OPTIONAL); + ck_assert_int_eq(verify_name_allowed_with_soa("example2.local", + NULL, TEST_LOCAL_SOA_NO), USE_NAME_RESULT_AUTHORITATIVE); + /* TEST_LOCAL_SOA_AUTO would test actual DNS on host, skip that. */ +} +END_TEST + +// Calls verify_name_allowed by first creating a memfile to read from. +static int verify_name_allowed_from_string(const char* name, + const char* file_contents) { + FILE* f = fmemopen((void*)file_contents, strlen(file_contents), "r"); + int result = verify_name_allowed(name, f); + fclose(f); + return result; +} + +// Tests verify_name_allowed with empty config. +// Nothing is permitted. +START_TEST(test_verify_name_allowed_empty) { + const char allow_file[] = ""; + + ck_assert_int_eq( + verify_name_allowed_from_string("example.local", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.local.", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("com.example.local", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("com.example.local.", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq(verify_name_allowed_from_string("example.com", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.com.", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.local.com", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.local.com.", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq(verify_name_allowed_from_string("", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq(verify_name_allowed_from_string(".", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); +} +END_TEST + +// Tests verify_name_allowed with the standard config. +// .local is unconditionally permitted, without SOA check. +// Multi-label names are allowed. +START_TEST(test_verify_name_allowed_default) { + const char allow_file[] = "# /etc/mdns.allow\n" + ".local.\n" + ".local\n"; + + ck_assert_int_eq( + verify_name_allowed_from_string("example.local", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.local.", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("com.example.local", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("com.example.local.", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq(verify_name_allowed_from_string("example.com", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.com.", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.local.com", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.local.com.", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq(verify_name_allowed_from_string("", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq(verify_name_allowed_from_string(".", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); +} +END_TEST + +// Tests verify_name_allowed with wildcard. +// Everything is permitted, with no SOA check. +// Multi-label names are allowed. +START_TEST(test_verify_name_allowed_wildcard) { + const char allow_file[] = "*\n"; + + ck_assert_int_eq( + verify_name_allowed_from_string("example.local", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.local.", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("com.example.local", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("com.example.local.", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq(verify_name_allowed_from_string("example.com", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.com.", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.local.com", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.local.com.", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq(verify_name_allowed_from_string("", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq(verify_name_allowed_from_string(".", allow_file), + VERIFY_NAME_RESULT_ALLOWED); +} +END_TEST + +// Tests verify_name_allowed with too-long lines. +START_TEST(test_verify_name_allowed_too_long) { + const char allow_file[] = + "# /etc/mdns.allow\n" + ".local." + " " // 50 spaces + " " // 50 spaces + " " // 50 spaces + "\n" + ".local\n"; + + ck_assert_int_eq( + verify_name_allowed_from_string("example.local", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.local.", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("com.example.local", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("com.example.local.", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq(verify_name_allowed_from_string("example.com", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.com.", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.local.com", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.local.com.", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq(verify_name_allowed_from_string("", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq(verify_name_allowed_from_string(".", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); +} +END_TEST + +// Tests verify_name_allowed with too-long non-empty lines. +START_TEST(test_verify_name_allowed_too_long2) { + const char allow_file[] = + "# /etc/mdns.allow\n" + ".aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" // 50 characters + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" // 50 characters + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" // 50 characters + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" // 50 characters + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" // 50 characters + "\n" + ".local.\n" + ".local\n"; + + // The input is truncated at 127 bytes, so we allow this string. + ck_assert_int_eq( + verify_name_allowed_from_string( + "example" + ".aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" // 50 + // characters + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" // 50 + // characters + "aaaaaaaaaaaaaaaaaaaaaaaaaaa", // 27 characters + allow_file), + VERIFY_NAME_RESULT_ALLOWED); + + // Even though this exactly matches the item in the allow file, + // it is too long. + ck_assert_int_eq( + verify_name_allowed_from_string( + "example" + ".aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" // 50 + // characters + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" // 50 + // characters + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" // 50 + // characters + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" // 50 + // characters + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", // 50 + // characters + allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + + ck_assert_int_eq( + verify_name_allowed_from_string("example.local", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.local.", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("com.example.local", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("com.example.local.", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq(verify_name_allowed_from_string("example.com", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.com.", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.local.com", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.local.com.", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq(verify_name_allowed_from_string("", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq(verify_name_allowed_from_string(".", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); +} +END_TEST + +// Tests verify_name_allowed with a custom config. +START_TEST(test_verify_name_allowed_com_and_local) { + const char allow_file[] = "# /etc/mdns.allow\n" + ".com.\n" + ".com\n" + ".local.\n" + ".local\n"; + + ck_assert_int_eq( + verify_name_allowed_from_string("example.local", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.local.", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("com.example.local", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("com.example.local.", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq(verify_name_allowed_from_string("example.com", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.com.", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.local.com", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.local.com.", allow_file), + VERIFY_NAME_RESULT_ALLOWED); + ck_assert_int_eq(verify_name_allowed_from_string("example.net", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq( + verify_name_allowed_from_string("example.net.", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq(verify_name_allowed_from_string("", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); + ck_assert_int_eq(verify_name_allowed_from_string(".", allow_file), + VERIFY_NAME_RESULT_NOT_ALLOWED); +} +END_TEST + +// Tests ends_with. +START_TEST(test_ends_with) { + ck_assert(ends_with("", "")); + ck_assert(!ends_with("", " ")); + ck_assert(!ends_with("", "z")); + ck_assert(ends_with("z", "")); + ck_assert(ends_with("z", "z")); + ck_assert(!ends_with("z", "zz")); + ck_assert(ends_with("example.local", ".local")); + ck_assert(ends_with("example.local.", ".local.")); + ck_assert(!ends_with("example.local.", ".local")); + ck_assert(!ends_with("example.local.", ".local")); +} +END_TEST + +// Tests label_count. +START_TEST(test_label_count) { + ck_assert_int_eq(label_count(""), 1); + ck_assert_int_eq(label_count("."), 1); + ck_assert_int_eq(label_count("local"), 1); + ck_assert_int_eq(label_count("local."), 1); + ck_assert_int_eq(label_count("foo.local"), 2); + ck_assert_int_eq(label_count("foo.local."), 2); + ck_assert_int_eq(label_count("bar.foo.local"), 3); + ck_assert_int_eq(label_count("bar.foo.local."), 3); + ck_assert_int_eq(label_count("my-foo.local"), 2); + ck_assert_int_eq(label_count("my-foo.local."), 2); +} +END_TEST + +// Tests for buffer_t functions. + +START_TEST(test_buffer_alloc_too_large_returns_null) { + char *buffer = malloc(100); + buffer_t buf; + buffer_init(&buf, buffer, 100); + + ck_assert_ptr_null(buffer_alloc(&buf, 101)); + free(buffer); +} +END_TEST + +START_TEST(test_buffer_alloc_just_right_returns_nonnull) { + char *buffer = malloc(100); + buffer_t buf; + buffer_init(&buf, buffer, 100); + + ck_assert_ptr_nonnull(buffer_alloc(&buf, 100)); + free(buffer); +} +END_TEST + +START_TEST(test_unaligned_buffer_alloc_returns_aligned) { + char *buffer = malloc(1000); + buffer_t buf; + + for (size_t i = 0; i < 32; i++) { + buffer_init(&buf, buffer + i, 1000 - i); + char* ptr = buffer_alloc(&buf, 10); + ck_assert_uint_eq((uintptr_t)ptr % sizeof(void*), 0); + } + free(buffer); +} +END_TEST + +START_TEST(test_buffer_alloc_returns_aligned) { + char *buffer = malloc(1000); + buffer_t buf; + buffer_init(&buf, buffer, 1000); + + for (size_t i = 0; i < 32; i++) { + char* ptr = buffer_alloc(&buf, i); + ck_assert_ptr_nonnull(ptr); + ck_assert_uint_eq((uintptr_t)ptr % sizeof(void*), 0); + } + free(buffer); +} +END_TEST + +START_TEST(test_null_buffer_zero_alloc_returns_nonnull) { + buffer_t buf; + buffer_init(&buf, NULL, 0); + + ck_assert_ptr_nonnull(buffer_alloc(&buf, 0)); +} +END_TEST + +START_TEST(test_zero_buffer_zero_alloc_returns_nonnull) { + char *buffer = malloc(1); + buffer_t buf; + buffer_init(&buf, buffer, 0); + + ck_assert_ptr_nonnull(buffer_alloc(&buf, 0)); + free(buffer); +} +END_TEST + +START_TEST(test_nonzero_buffer_zero_alloc_returns_nonnull) { + char *buffer = malloc(100); + buffer_t buf; + buffer_init(&buf, buffer, 100); + + ck_assert_ptr_nonnull(buffer_alloc(&buf, 0)); + free(buffer); +} +END_TEST + +START_TEST(test_null_buffer_nonzero_alloc_returns_null) { + buffer_t buf; + buffer_init(&buf, NULL, 0); + + ck_assert_ptr_null(buffer_alloc(&buf, 1)); +} +END_TEST + +START_TEST(test_zero_buffer_nonzero_alloc_returns_null) { + char *buffer = malloc(1); + buffer_t buf; + buffer_init(&buf, buffer, 0); + + ck_assert_ptr_null(buffer_alloc(&buf, 1)); + free(buffer); +} +END_TEST + +START_TEST(test_buffer_tiny_alloc_returns_nonnull) { + char *buffer = malloc(100); + buffer_t buf; + buffer_init(&buf, buffer, 100); + + ck_assert_ptr_nonnull(buffer_alloc(&buf, 1)); + free(buffer); +} +END_TEST + +START_TEST(test_tiny_buffer_tiny_alloc_returns_nonnull) { + char* buffer = malloc(1); + buffer_t buf; + buffer_init(&buf, buffer, 1); + + ck_assert_ptr_nonnull(buffer_alloc(&buf, 1)); + free(buffer); +} +END_TEST + +START_TEST(test_tiny_unaligned_buffer_tiny_alloc_returns_null) { + char* buffer = malloc(2); + buffer_t buf; + buffer_init(&buf, buffer + 1, 1); + + ck_assert_ptr_null(buffer_alloc(&buf, 1)); + free(buffer); +} +END_TEST + +START_TEST(test_tiny_buffer_second_alloc_returns_null) { + char* buffer = malloc(2); + buffer_t buf; + buffer_init(&buf, buffer, 2); + + ck_assert_ptr_nonnull(buffer_alloc(&buf, 1)); + ck_assert_ptr_null(buffer_alloc(&buf, 1)); // With alignment, out of room. + free(buffer); +} +END_TEST + +START_TEST(test_tiny_buffer_one_too_big_alloc_returns_null) { + char* buffer = malloc(1); // Need to malloc to get pre-aligned buffer. + buffer_t buf; + buffer_init(&buf, buffer, 1); + + ck_assert_ptr_null(buffer_alloc(&buf, 2)); + free(buffer); +} +END_TEST + +START_TEST(test_buffer_alloc_returns_zeroed_memory) { + char *buffer = malloc(100); + memset(buffer, 0xFF, 100); + + char zero[100]; + memset(zero, 0, sizeof(zero)); + + buffer_t buf; + buffer_init(&buf, buffer, 100); + ck_assert_mem_eq(buffer_alloc(&buf, 50), zero, 50); + free(buffer); +} +END_TEST + +static const uint8_t ipv6_doc_prefix[16] = { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xb8, 0x0d, 0x01, 0x20}; // Documentation prefix +static const uint32_t ipv4_test_addr = 0xc6336401; // 198.51.100.1 (TEST-NET-2) + +static query_address_result_t create_address_result(int offset, int af) { + query_address_result_t result; + + if (af == AF_UNSPEC) { + // Alternate between IPv4 and IPv6. + af = offset % 2 ? AF_INET : AF_INET6; + result.af = af; + } + + switch (af) { + case AF_INET: + result.address.ipv4.address = htonl(ipv4_test_addr + offset); + break; + case AF_INET6: + memcpy(result.address.ipv6.address, ipv6_doc_prefix, + sizeof ipv6_doc_prefix); + result.address.ipv6.address[0] = offset; + result.scopeid = (offset / 2) % 3; + break; + } + return result; +} + +#ifndef __FreeBSD__ +static void validate_addrtuples(struct gaih_addrtuple* pat, + const char* expected_name, int expected_count) { + int i = 0; + while (pat != NULL) { + ck_assert_str_eq(pat->name, expected_name); + int expected_af = i % 2 ? AF_INET : AF_INET6; + ck_assert_int_eq(pat->family, expected_af); + + uint32_t expected_ipv4 = htonl(ipv4_test_addr + i); + uint8_t expected_ipv6[16]; + memcpy(expected_ipv6, ipv6_doc_prefix, sizeof ipv6_doc_prefix); + expected_ipv6[0] = i; + switch (expected_af) { + case AF_INET: + ck_assert_mem_eq(pat->addr, &expected_ipv4, sizeof expected_ipv4); + break; + case AF_INET6: + ck_assert_mem_eq(pat->addr, expected_ipv6, sizeof expected_ipv6); + ck_assert_int_eq(pat->scopeid, (i / 2) % 3); + break; + } + + i++; + pat = pat->next; + } + ck_assert_int_eq(i, expected_count); +} +#endif + +static userdata_t create_address_userdata(int num_addresses, int af) { + ck_assert_int_le(num_addresses, MAX_ENTRIES); + + userdata_t u; + u.count = 0; + for (int i = 0; i < num_addresses; i++) { + query_address_result_t result = create_address_result(i, af); + append_address_to_userdata(&result, &u); + } + return u; +} + +static void poison(char* buf, size_t buflen) { memset(buf, 0x55, buflen); } + +static void validate_poison(char* buf, size_t buflen, size_t full_buflen) { + size_t excess = full_buflen - buflen; + char poison[excess]; + memset(poison, 0x55, sizeof(poison)); + ck_assert_mem_eq(buf + buflen, poison, excess); +} + +static void validate_hostent(struct hostent* hostent, const char* name, int af, + int expected_count) { + ck_assert_str_eq(name, hostent->h_name); + ck_assert_ptr_nonnull(hostent->h_aliases); + ck_assert_ptr_null(hostent->h_aliases[0]); + ck_assert_int_eq(af, hostent->h_addrtype); + ck_assert_int_eq(af == AF_INET ? sizeof(ipv4_address_t) + : sizeof(ipv6_address_t), + hostent->h_length); + ck_assert_ptr_nonnull(hostent->h_addr_list); + + int i = 0; + char** addr = hostent->h_addr_list; + while (*addr != NULL) { + uint32_t expected_ipv4 = htonl(ipv4_test_addr + i); + uint8_t expected_ipv6[16]; + memcpy(expected_ipv6, ipv6_doc_prefix, sizeof ipv6_doc_prefix); + expected_ipv6[0] = i; + switch (af) { + case AF_INET: + ck_assert_mem_eq(*addr, &expected_ipv4, sizeof expected_ipv4); + break; + case AF_INET6: + ck_assert_mem_eq(*addr, expected_ipv6, sizeof expected_ipv6); + break; + } + addr++; + i++; + } + ck_assert_int_eq(expected_count, i); +} + +// Tests for convert_userdata_to_addrtuple. + +#ifndef __FreeBSD__ +START_TEST(test_userdata_to_addrtuple_returns_tuples) { + userdata_t u = create_address_userdata(16, AF_UNSPEC); + struct gaih_addrtuple* pat = NULL; + char buffer[2048]; + int errnop; + int h_errnop; + + buffer_t buf; + buffer_init(&buf, buffer, sizeof(buffer)); + enum nss_status status = convert_userdata_to_addrtuple( + &u, "example.local", &pat, &buf, &errnop, &h_errnop); + ck_assert_int_eq(status, NSS_STATUS_SUCCESS); + validate_addrtuples(pat, "example.local", 16); +} +END_TEST + +START_TEST(test_userdata_to_addrtuple_buffer_too_small_returns_erange) { + userdata_t u = create_address_userdata(8, AF_UNSPEC); + struct gaih_addrtuple* pat = NULL; + char buffer[10]; + int errnop; + int h_errnop; + + buffer_t buf; + buffer_init(&buf, buffer, 0); + enum nss_status status = convert_userdata_to_addrtuple( + &u, "example.local", &pat, &buf, &errnop, &h_errnop); + ck_assert_int_eq(errnop, ERANGE); + ck_assert_int_eq(h_errnop, NO_RECOVERY); + ck_assert_int_eq(status, NSS_STATUS_TRYAGAIN); +} +END_TEST + +START_TEST(test_userdata_to_addrtuple_smallest_buffer_eventually_works) { + userdata_t u = create_address_userdata(16, AF_UNSPEC); + struct gaih_addrtuple* pat; + char buffer[2048]; + int errnop; + int h_errnop; + + enum nss_status status = 0; + size_t buflen; + for (buflen = 0; buflen < sizeof(buffer); buflen++) { + poison(buffer, sizeof(buffer)); + errnop = h_errnop = 0; + buffer_t buf; + pat = NULL; + buffer_init(&buf, buffer, buflen); + status = convert_userdata_to_addrtuple(&u, "example.local", &pat, &buf, + &errnop, &h_errnop); + validate_poison(buffer, buflen, sizeof(buffer)); + if (errnop != ERANGE) + break; + if (h_errnop != NO_RECOVERY) + break; + if (status != NSS_STATUS_TRYAGAIN) + break; + } + ck_assert_int_eq(status, NSS_STATUS_SUCCESS); + validate_addrtuples(pat, "example.local", 16); +} +END_TEST + +START_TEST(test_userdata_to_addrtuple_nonnull_pat_is_used) { + userdata_t u = create_address_userdata(16, AF_UNSPEC); + struct gaih_addrtuple tuple; + struct gaih_addrtuple* pat = &tuple; + char buffer[2048]; + int errnop; + int h_errnop; + + memset(&tuple, 0, sizeof tuple); + buffer_t buf; + buffer_init(&buf, buffer, sizeof(buffer)); + enum nss_status status = convert_userdata_to_addrtuple( + &u, "example.local", &pat, &buf, &errnop, &h_errnop); + ck_assert_int_eq(status, NSS_STATUS_SUCCESS); + validate_addrtuples(&tuple, "example.local", 16); +} +END_TEST +#endif + +// Tests for convert_userdata_for_name_to_hostent. + +START_TEST(test_userdata_for_name_to_hostent_returns_hostent_4) { + userdata_t u = create_address_userdata(16, AF_INET); + struct hostent result; + char buffer[2048]; + int errnop; + int h_errnop; + + buffer_t buf; + buffer_init(&buf, buffer, sizeof(buffer)); + enum nss_status status = convert_userdata_for_name_to_hostent( + &u, "example.local", AF_INET, &result, &buf, &errnop, &h_errnop); + ck_assert_int_eq(status, NSS_STATUS_SUCCESS); + validate_hostent(&result, "example.local", AF_INET, 16); +} +END_TEST + +START_TEST(test_userdata_for_name_to_hostent_returns_hostent_6) { + userdata_t u = create_address_userdata(16, AF_INET6); + struct hostent result; + char buffer[2048]; + int errnop; + int h_errnop; + + buffer_t buf; + buffer_init(&buf, buffer, sizeof(buffer)); + enum nss_status status = convert_userdata_for_name_to_hostent( + &u, "example.local", AF_INET6, &result, &buf, &errnop, &h_errnop); + ck_assert_int_eq(status, NSS_STATUS_SUCCESS); + validate_hostent(&result, "example.local", AF_INET6, 16); +} +END_TEST + +START_TEST(test_userdata_for_name_to_hostent_buffer_too_small_returns_erange) { + userdata_t u = create_address_userdata(16, AF_INET); + struct hostent result; + char buffer[10]; + int errnop; + int h_errnop; + + buffer_t buf; + buffer_init(&buf, buffer, 0); + enum nss_status status = convert_userdata_for_name_to_hostent( + &u, "example.local", AF_INET, &result, &buf, &errnop, &h_errnop); + ck_assert_int_eq(errnop, ERANGE); + ck_assert_int_eq(h_errnop, NO_RECOVERY); + ck_assert_int_eq(status, NSS_STATUS_TRYAGAIN); +} +END_TEST + +START_TEST( + test_userdata_for_name_to_hostent_smallest_buffer_eventually_works_4) { + userdata_t u = create_address_userdata(16, AF_INET); + struct hostent result; + char buffer[2048]; + int errnop; + int h_errnop; + + enum nss_status status = 0; + size_t buflen; + for (buflen = 0; buflen < sizeof(buffer); buflen++) { + poison(buffer, sizeof(buffer)); + errnop = h_errnop = 0; + + buffer_t buf; + buffer_init(&buf, buffer, buflen); + status = convert_userdata_for_name_to_hostent( + &u, "example.local", AF_INET, &result, &buf, &errnop, &h_errnop); + validate_poison(buffer, buflen, sizeof(buffer)); + if (errnop != ERANGE) + break; + if (h_errnop != NO_RECOVERY) + break; + if (status != NSS_STATUS_TRYAGAIN) + break; + } + ck_assert_int_eq(status, NSS_STATUS_SUCCESS); + validate_hostent(&result, "example.local", AF_INET, 16); +} +END_TEST + +START_TEST( + test_userdata_for_name_to_hostent_smallest_buffer_eventually_works_6) { + userdata_t u = create_address_userdata(16, AF_INET6); + struct hostent result; + char buffer[2048]; + int errnop; + int h_errnop; + + enum nss_status status = 0; + size_t buflen; + for (buflen = 0; buflen < sizeof(buffer); buflen++) { + poison(buffer, sizeof(buffer)); + errnop = h_errnop = 0; + buffer_t buf; + buffer_init(&buf, buffer, buflen); + status = convert_userdata_for_name_to_hostent( + &u, "example.local", AF_INET6, &result, &buf, &errnop, &h_errnop); + validate_poison(buffer, buflen, sizeof(buffer)); + if (errnop != ERANGE) + break; + if (h_errnop != NO_RECOVERY) + break; + if (status != NSS_STATUS_TRYAGAIN) + break; + } + ck_assert_int_eq(status, NSS_STATUS_SUCCESS); + validate_hostent(&result, "example.local", AF_INET6, 16); +} +END_TEST + +// Tests for convert_name_and_addr_to_hostent. + +START_TEST(test_name_and_addr_to_hostent_returns_hostent_4) { + struct hostent result; + char buffer[2048]; + int errnop; + int h_errnop; + uint32_t ipv4 = htonl(ipv4_test_addr); + + buffer_t buf; + buffer_init(&buf, buffer, sizeof(buffer)); + enum nss_status status = convert_name_and_addr_to_hostent( + "example.local", &ipv4, sizeof ipv4, AF_INET, &result, &buf, &errnop, + &h_errnop); + ck_assert_int_eq(status, NSS_STATUS_SUCCESS); + validate_hostent(&result, "example.local", AF_INET, 1); +} +END_TEST + +START_TEST(test_name_and_addr_to_hostent_returns_hostent_6) { + struct hostent result; + char buffer[2048]; + int errnop; + int h_errnop; + + buffer_t buf; + buffer_init(&buf, buffer, sizeof(buffer)); + enum nss_status status = convert_name_and_addr_to_hostent( + "example.local", &ipv6_doc_prefix, sizeof ipv6_doc_prefix, AF_INET6, + &result, &buf, &errnop, &h_errnop); + ck_assert_int_eq(status, NSS_STATUS_SUCCESS); + validate_hostent(&result, "example.local", AF_INET6, 1); +} +END_TEST + +START_TEST(test_name_and_addr_to_hostent_buffer_too_small_returns_erange) { + struct hostent result; + char buffer[10]; + int errnop; + int h_errnop; + uint32_t ipv4 = htonl(ipv4_test_addr); + + buffer_t buf; + buffer_init(&buf, buffer, sizeof(buffer)); + enum nss_status status = convert_name_and_addr_to_hostent( + "example.local", &ipv4, sizeof ipv4, AF_INET, &result, &buf, &errnop, + &h_errnop); + ck_assert_int_eq(errnop, ERANGE); + ck_assert_int_eq(h_errnop, NO_RECOVERY); + ck_assert_int_eq(status, NSS_STATUS_TRYAGAIN); +} +END_TEST + +START_TEST(test_name_and_addr_to_hostent_smallest_buffer_eventually_works_4) { + struct hostent result; + char buffer[2048]; + int errnop; + int h_errnop; + uint32_t ipv4 = htonl(ipv4_test_addr); + enum nss_status status = 0; + size_t buflen; + for (buflen = 0; buflen < sizeof(buffer); buflen++) { + poison(buffer, sizeof(buffer)); + errnop = h_errnop = 0; + buffer_t buf; + buffer_init(&buf, buffer, buflen); + status = convert_name_and_addr_to_hostent("example.local", &ipv4, + sizeof ipv4, AF_INET, &result, + &buf, &errnop, &h_errnop); + validate_poison(buffer, buflen, sizeof(buffer)); + if (errnop != ERANGE) + break; + if (h_errnop != NO_RECOVERY) + break; + if (status != NSS_STATUS_TRYAGAIN) + break; + } + ck_assert_int_eq(status, NSS_STATUS_SUCCESS); + validate_hostent(&result, "example.local", AF_INET, 1); +} +END_TEST + +START_TEST(test_name_and_addr_to_hostent_smallest_buffer_eventually_works_6) { + struct hostent result; + char buffer[2048]; + int errnop; + int h_errnop; + enum nss_status status = 0; + size_t buflen; + for (buflen = 0; buflen < sizeof(buffer); buflen++) { + poison(buffer, sizeof(buffer)); + errnop = h_errnop = 0; + buffer_t buf; + buffer_init(&buf, buffer, buflen); + status = convert_name_and_addr_to_hostent( + "example.local", &ipv6_doc_prefix, sizeof ipv6_doc_prefix, AF_INET6, + &result, &buf, &errnop, &h_errnop); + validate_poison(buffer, buflen, sizeof(buffer)); + if (errnop != ERANGE) + break; + if (h_errnop != NO_RECOVERY) + break; + if (status != NSS_STATUS_TRYAGAIN) + break; + } + ck_assert_int_eq(status, NSS_STATUS_SUCCESS); + validate_hostent(&result, "example.local", AF_INET6, 1); +} +END_TEST + +// Boilerplate from https://libcheck.github.io/check/doc/check_html/check_3.html +static Suite* util_suite(void) { + Suite* s = suite_create("util"); + + TCase* tc_verify_name = tcase_create("verify_name"); + tcase_add_test(tc_verify_name, test_verify_name_allowed_minimal); + tcase_add_test(tc_verify_name, test_verify_name_allowed_default); + tcase_add_test(tc_verify_name, test_verify_name_allowed_empty); + tcase_add_test(tc_verify_name, test_verify_name_allowed_wildcard); + tcase_add_test(tc_verify_name, test_verify_name_allowed_too_long); + tcase_add_test(tc_verify_name, test_verify_name_allowed_too_long2); + tcase_add_test(tc_verify_name, test_verify_name_allowed_com_and_local); + suite_add_tcase(s, tc_verify_name); + + TCase* tc_ends_with = tcase_create("ends_with"); + tcase_add_test(tc_ends_with, test_ends_with); + suite_add_tcase(s, tc_ends_with); + + TCase* tc_label_count = tcase_create("label_count"); + tcase_add_test(tc_label_count, test_label_count); + suite_add_tcase(s, tc_label_count); + + TCase* tc_buffer = tcase_create("buffer"); + tcase_add_test(tc_buffer, test_buffer_alloc_too_large_returns_null); + tcase_add_test(tc_buffer, test_buffer_alloc_just_right_returns_nonnull); + tcase_add_test(tc_buffer, test_unaligned_buffer_alloc_returns_aligned); + tcase_add_test(tc_buffer, test_buffer_alloc_returns_aligned); + tcase_add_test(tc_buffer, test_null_buffer_zero_alloc_returns_nonnull); + tcase_add_test(tc_buffer, test_zero_buffer_zero_alloc_returns_nonnull); + tcase_add_test(tc_buffer, test_nonzero_buffer_zero_alloc_returns_nonnull); + tcase_add_test(tc_buffer, test_null_buffer_nonzero_alloc_returns_null); + tcase_add_test(tc_buffer, test_zero_buffer_nonzero_alloc_returns_null); + tcase_add_test(tc_buffer, test_buffer_tiny_alloc_returns_nonnull); + tcase_add_test(tc_buffer, test_tiny_buffer_tiny_alloc_returns_nonnull); + tcase_add_test(tc_buffer, + test_tiny_unaligned_buffer_tiny_alloc_returns_null); + tcase_add_test(tc_buffer, test_tiny_buffer_second_alloc_returns_null); + tcase_add_test(tc_buffer, test_tiny_buffer_one_too_big_alloc_returns_null); + tcase_add_test(tc_buffer, test_buffer_alloc_returns_zeroed_memory); + suite_add_tcase(s, tc_buffer); + +#ifndef __FreeBSD__ + TCase* tc_userdata_to_addrtuple = tcase_create("userdata_to_addrtuple"); + tcase_add_test(tc_userdata_to_addrtuple, + test_userdata_to_addrtuple_returns_tuples); + tcase_add_test(tc_userdata_to_addrtuple, + test_userdata_to_addrtuple_buffer_too_small_returns_erange); + tcase_add_test(tc_userdata_to_addrtuple, + test_userdata_to_addrtuple_smallest_buffer_eventually_works); + tcase_add_test(tc_userdata_to_addrtuple, + test_userdata_to_addrtuple_nonnull_pat_is_used); + suite_add_tcase(s, tc_userdata_to_addrtuple); +#endif + + TCase* tc_userdata_for_name_to_hostent = + tcase_create("userdata_for_name_to_hostent"); + tcase_add_test(tc_userdata_for_name_to_hostent, + test_userdata_for_name_to_hostent_returns_hostent_4); + tcase_add_test(tc_userdata_for_name_to_hostent, + test_userdata_for_name_to_hostent_returns_hostent_6); + tcase_add_test( + tc_userdata_for_name_to_hostent, + test_userdata_for_name_to_hostent_buffer_too_small_returns_erange); + tcase_add_test( + tc_userdata_for_name_to_hostent, + test_userdata_for_name_to_hostent_smallest_buffer_eventually_works_4); + tcase_add_test( + tc_userdata_for_name_to_hostent, + test_userdata_for_name_to_hostent_smallest_buffer_eventually_works_6); + suite_add_tcase(s, tc_userdata_for_name_to_hostent); + + TCase* tc_name_and_addr_to_hostent = + tcase_create("name_and_addr_to_hostent"); + tcase_add_test(tc_name_and_addr_to_hostent, + test_name_and_addr_to_hostent_returns_hostent_4); + tcase_add_test(tc_name_and_addr_to_hostent, + test_name_and_addr_to_hostent_returns_hostent_6); + tcase_add_test( + tc_name_and_addr_to_hostent, + test_name_and_addr_to_hostent_buffer_too_small_returns_erange); + tcase_add_test( + tc_name_and_addr_to_hostent, + test_name_and_addr_to_hostent_smallest_buffer_eventually_works_4); + tcase_add_test( + tc_name_and_addr_to_hostent, + test_name_and_addr_to_hostent_smallest_buffer_eventually_works_6); + suite_add_tcase(s, tc_name_and_addr_to_hostent); + + return s; +} + +int main(void) { + int number_failed; + Suite* s; + SRunner* sr; + + s = util_suite(); + sr = srunner_create(s); + + srunner_run_all(sr, CK_VERBOSE); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} From c7abd8f4e17bbec5ac0a0aa6edfd73daa15d2c4e Mon Sep 17 00:00:00 2001 From: Eric Sauvageau Date: Wed, 17 Jul 2024 22:20:23 -0400 Subject: [PATCH 9/9] libnss-mdns: added build recipe --- release/src/router/Makefile | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/release/src/router/Makefile b/release/src/router/Makefile index c3e9cd39684..a824bf24f58 100644 --- a/release/src/router/Makefile +++ b/release/src/router/Makefile @@ -1536,6 +1536,7 @@ ifeq ($(or $(RTCONFIG_TIMEMACHINE),$(RTCONFIG_MDNS)),y) obj-y += libdaemon obj-y += expat-2.0.1 obj-y += avahi +obj-y += libnss-mdns else ifeq ($(or $(RTCONFIG_MEDIA_SERVER),$(RTCONFIG_BWDPI)),y) obj-y += mDNSResponder @@ -9427,6 +9428,25 @@ iproute2-5.11.0-clean: -@$(MAKE) -C iproute2-5.11.0 clean -rm -f iproute2-5.11.0/iproute2-5.11.0/Config +libnss-mdns/configure: + cd libnss-mdns && autoreconf --force --install + +libnss-mdns/Makefile: libnss-mdns/configure + cd libnss-mdns && $(CONFIGURE) LDFLAGS="$(LDFLAGS) -L$(STAGEDIR)/usr/lib -ldl -lpthread $(EXTRA_LDFLAGS)" \ + CFLAGS="$(CFLAGS) -I$(STAGEDIR)/usr/include -I$(TOP)/shared -I$(SRCBASE)/include" \ + --prefix=/usr --sysconfdir=/tmp localstatedir=/var --with-distro=none \ + --disable-tests --disable-static --enable-shared + +libnss-mdns: libnss-mdns/Makefile + @$(SEP) + @$(MAKE) -C libnss-mdns + +libnss-mdns-install: libnss-mdns + install -D libnss-mdns/.libs/libnss_mdns4_minimal.so.2 $(INSTALLDIR)/libnss-mdns/usr/lib/libnss_mdns4_minimal.so.2 + install -D libnss-mdns/.libs/libnss_mdns4.so.2 $(INSTALLDIR)/libnss-mdns/usr/lib/libnss_mdns4.so.2 + $(STRIP) $(INSTALLDIR)/libnss-mdns/usr/lib/libnss_mdns4_minimal.so.2 + $(STRIP) $(INSTALLDIR)/libnss-mdns/usr/lib/libnss_mdns4.so.2 + # End merlin components readline-6.2/Makefile: readline-6.2/configure