����JFIFXX�����    $.' ",#(7),01444'9=82<.342  2!!22222222222222222222222222222222222222222222222222����"��4�� ���,�PG"Z_�4�˷����kjز�Z�,F+��_z�,�© �����zh6�٨�ic�fu���#ډb���_�N�?��wQ���5-�~�I���8����TK<5o�Iv-�����k�_U_�����~b�M��d����Ӝ�U�Hh��?]��E�w��Q���k�{��_}qFW7HTՑ��Y��F�?_�'ϔ��_�Ջt��=||I ��6�έ"�����D���/[�k�9���Y�8ds|\���Ҿp6�Ҵ���]��.����6�z<�v��@]�i%��$j��~�g��J>��no����pM[me�i$[����s�o�ᘨ�˸ nɜG-�ĨU�ycP�3.DB�li�;��hj���x7Z^�N�h������N3u{�:j�x�힞��#M&��jL P@_���� P��&��o8������9�����@Sz6�t7#O�ߋ �s}Yf�T���lmr����Z)'N��k�۞p����w\�Tȯ?�8`�O��i{wﭹW�[�r�� ��Q4F�׊���3m&L�=��h3����z~��#�\�l :�F,j@�� ʱ�wQT����8�"kJO���6�֚l����}���R�>ډK���]��y����&����p�}b��;N�1�m�r$�|��7�>e�@B�TM*-iH��g�D�)� E�m�|�ؘbҗ�a��Ҿ����t4���o���G��*oCN�rP���Q��@z,|?W[0�����:�n,jWiE��W��$~/�hp\��?��{(�0���+�Y8rΟ�+����>S-S����VN;�}�s?.����� w�9��˟<���Mq4�Wv'��{)0�1mB��V����W[�����8�/<� �%���wT^�5���b��)iM� pg�N�&ݝ��VO~�q���u���9� ����!��J27����$O-���! �:�%H��� ـ����y�ΠM=t{!S�� oK8������t<����è:a������[�����ա�H���~��w��Qz`�po�^ ����Q��n� �,uu�C�$ ^���,������8�#��:�6��e�|~���!�3�3.�\0��q��o�4`.|� ����y�Q�`~;�d�ׯ,��O�Zw�������`73�v�܋�<���Ȏ�� ـ4k��5�K�a�u�=9Yd��$>x�A�&�� j0� ���vF��� Y�|�y��� ~�6�@c��1vOp�Ig����4��l�OD���L����� R���c���j�_�uX6��3?nk��Wy�f;^*B� ��@�~a�`��Eu������+���6�L��.ü>��}y���}_�O�6�͐�:�YrG�X��kG�����l^w���~㒶sy��Iu�!� W ��X��N�7BV��O��!X�2����wvG�R�f�T#�����t�/?���%8�^�W�aT��G�cL�M���I��(J����1~�8�?aT ���]����AS�E��(��*E}� 2��#I/�׍qz��^t�̔���b�Yz4x���t�){ OH��+(E��A&�N�������XT��o��"�XC��'���)}�J�z�p� ��~5�}�^����+�6����w��c��Q�|Lp�d�H��}�(�.|����k��c4^�"�����Z?ȕ ��a<�L�!039C� �Eu�C�F�Ew�ç ;�n?�*o���B�8�bʝ���'#Rqf���M}7����]����s2tcS{�\icTx;�\��7K���P���ʇ Z O-��~��c>"��?�������P��E��O�8��@�8��G��Q�g�a�Վ���󁶠�䧘��_%#r�>�1�z�a��eb��qcPѵ��n���#L��� =��׀t� L�7�`��V���A{�C:�g���e@�w1 Xp3�c3�ġ����p��M"'-�@n4���fG��B3�DJ�8[Jo�ߐ���gK)ƛ��$���� ���8�3�����+���� �����6�ʻ���� ���S�kI�*KZlT _`���?��K����QK�d����B`�s}�>���`��*�>��,*@J�d�oF*����弝��O}�k��s��]��y�ߘ��c1G�V���<=�7��7����6�q�PT��tXԀ�!9*4�4Tހ3XΛex�46���Y��D ����� �BdemDa����\�_l,��G�/���֌7���Y�](�xTt^%�GE�����4�}bT���ڹ�����;Y)���B�Q��u��>J/J �⮶.�XԄ��j�ݳ�+E��d ��r�5�_D�1 ��o�� �B�x�΢�#���<��W�����8���R6�@g�M�.��� dr�D��>(otU��@x=��~v���2� ӣ�d�oBd��3�eO�6�㣷�����ݜ6��6Y��Qz`��S��{���\P�~z m5{J/L��1������<�e�ͅPu�b�]�ϔ���'������f�b� Zpw��c`"��i���BD@:)ִ�:�]��hv�E�w���T�l��P���"Ju�}��وV J��G6��. J/�Qgl߭�e�����@�z�Zev2u�)]կ�����7x���s�M�-<ɯ�c��r�v�����@��$�ޮ}lk���a���'����>x��O\�ZFu>�����ck#��&:��`�$�ai�>2Δ����l���oF[h��lE�ܺ�Πk:)���`�� $[6�����9�����kOw�\|���8}������ބ:��񶐕��I�A1/�=�2[�,�!��.}gN#�u����b��� ~��݊��}34q����d�E��Lc��$��"�[q�U�硬g^��%B �z���r�pJ�ru%v\h1Y�ne`ǥ:g���pQM~�^�Xi� ��`S�:V29.�P���V�?B�k�� AEvw%�_�9C�Q����wKekPؠ�\�;Io d�{ ߞo�c1eP����\� `����E=���@K<�Y���eڼ�J���w����{av�F�'�M�@/J��+9p���|]�����Iw &`��8���&M�hg��[�{��Xj��%��Ӓ�$��(����ʹN���<>�I���RY���K2�NPlL�ɀ)��&e����B+ь����( � �JTx���_?EZ� }@ 6�U���뙢ط�z��dWI�n` D����噥�[��uV��"�G&Ú����2g�}&m��?ċ�"����Om#��������� ��{�ON��"S�X��Ne��ysQ���@Fn��Vg���dX�~nj�]J�<�K]:��FW��b�������62�=��5f����JKw��bf�X�55��~J �%^����:�-�QIE��P��v�nZum� z � ~ə ���� ���ة����;�f��\v���g�8�1��f24;�V���ǔ�)����9���1\��c��v�/'Ƞ�w�������$�4�R-��t���� e�6�/�ġ �̕Ecy�J���u�B���<�W�ַ~�w[B1L۲�-JS΂�{���΃������A��20�c#��@ 0!1@AP"#2Q`$3V�%45a6�FRUq��� ����^7ׅ,$n�������+��F�`��2X'��0vM��p�L=������5��8������u�p~���.�`r�����\���O��,ư�0oS ��_�M�����l���4�kv\JSd���x���SW�<��Ae�IX����������$I���w�:S���y���›R��9�Q[���,�5�;�@]�%���u�@ *ro�lbI �� ��+���%m:�͇ZV�����u�̉����θau<�fc�.����{�4Ա� �Q����*�Sm��8\ujqs]{kN���)qO�y�_*dJ�b�7���yQqI&9�ԌK!�M}�R�;������S�T���1���i[U�ɵz�]��U)V�S6���3$K{�ߊ<�(� E]Զ[ǼENg�����'�\?#)Dkf��J���o��v���'�%ƞ�&K�u�!��b�35LX�Ϸ��63$K�a�;�9>,R��W��3�3� d�JeTYE.Mϧ��-�o�j3+y��y^�c�������VO�9NV\nd�1 ��!͕_)a�v;����թ�M�lWR1��)El��P;��yوÏ�u 3�k�5Pr6<�⒲l�!˞*��u־�n�!�l:����UNW ��%��Chx8vL'��X�@��*��)���̮��ˍ��� ���D-M�+J�U�kvK����+�x8��cY������?�Ԡ��~3mo��|�u@[XeY�C�\Kp�x8�oC�C�&����N�~3-H���� ��MX�s�u<`���~"WL��$8ξ��3���a�)|:@�m�\���^�`�@ҷ)�5p+��6���p�%i)P M���ngc�����#0Aruz���RL+xSS?���ʮ}()#�t��mˇ!��0}}y����<�e� �-ή�Ԩ��X������ MF���ԙ~l L.3���}�V뽺�v�����멬��Nl�)�2����^�Iq��a��M��qG��T�����c3#������3U�Ǎ���}��לS�|qa��ڃ�+���-��2�f����/��bz��ڐ�� �ݼ[2�ç����k�X�2�* �Z�d���J�G����M*9W���s{��w���T��x��y,�in�O�v��]���n����P�$�JB@=4�OTI�n��e�22a\����q�d���%�$��(���:���: /*�K[PR�fr\nڙdN���F�n�$�4�[�� U�zƶ����� �mʋ���,�ao�u 3�z� �x��Kn����\[��VFmbE;�_U��&V�Gg�]L�۪&#n%�$ɯ�dG���D�TI=�%+AB�Ru#��b4�1�»x�cs�YzڙJG��f��Il��d�eF'T� iA��T���uC�$����Y��H?����[!G`}���ͪ� �纤Hv\������j�Ex�K���!���OiƸ�Yj�+u-<���'q����uN�*�r\��+�]���<�wOZ.fp�ێ��,-*)V?j-kÊ#�`�r��dV����(�ݽBk�����G�ƛk�QmUڗe��Z���f}|����8�8��a���i��3'J�����~G_�^���d�8w������ R�`(�~�.��u���l�s+g�bv���W���lGc}��u���afE~1�Ue������Z�0�8�=e�� f@/�jqEKQQ�J��oN��J���W5~M>$6�Lt�;$ʳ{���^��6�{����v6���ķܰg�V�cnn �~z�x�«�,2�u�?cE+Ș�H؎�%�Za�)���X>uW�Tz�Nyo����s���FQƤ��$��*�&�LLXL)�1�" L��eO��ɟ�9=���:t��Z���c��Ž���Y?�ӭV�wv�~,Y��r�ۗ�|�y��GaF�����C�����.�+� ���v1���fήJ�����]�S��T��B��n5sW}y�$��~z�'�c ��8 ��� ,! �p��VN�S��N�N�q��y8z˱�A��4��*��'������2n<�s���^ǧ˭P�Jޮɏ�U�G�L�J�*#��<�V��t7�8����TĜ>��i}K%,���)[��z�21z ?�N�i�n1?T�I�R#��m-�����������������1����lA�`��fT5+��ܐ�c�q՝��ʐ��,���3�f2U�եmab��#ŠdQ�y>\��)�SLY����w#��.���ʑ�f��� ,"+�w�~�N�'�c�O�3F�������N<���)j��&��,-� �љ���֊�_�zS���TǦ����w�>��?�������n��U仆�V���e�����0���$�C�d���rP �m�׈e�Xm�Vu� �L��.�bֹ��� �[Դaզ���*��\y�8�Է:�Ez\�0�Kq�C b��̘��cө���Q��=0Y��s�N��S.���3.���O�o:���#���v7�[#߫ ��5�܎�L���Er4���9n��COWlG�^��0k�%<���ZB���aB_���������'=��{i�v�l�$�uC���mƎҝ{�c㱼�y]���W�i ��ߧc��m�H� m�"�"�����;Y�ߝ�Z�Ǔ�����:S#��|}�y�,/k�Ld� TA�(�AI$+I3��;Y*���Z��}|��ӧO��d�v��..#:n��f>�>���ȶI�TX��� 8��y����"d�R�|�)0���=���n4��6ⲑ�+��r<�O�܂~zh�z����7ܓ�HH�Ga롏���nCo�>������a ���~]���R���̲c?�6(�q�;5%� |�uj�~z8R=X��I�V=�|{v�Gj\gc��q����z�؋%M�ߍ����1y��#��@f^���^�>N�����#x#۹��6�Y~�?�dfPO��{��P�4��V��u1E1J �*|���%���JN��`eWu�zk M6���q t[�� ��g�G���v��WIG��u_ft����5�j�"�Y�:T��ɐ���*�;� e5���4����q$C��2d�}���� _S�L#m�Yp��O�.�C�;��c����Hi#֩%+) �Ӎ��ƲV���SYź��g |���tj��3�8���r|���V��1#;.SQ�A[���S������#���`n�+���$��$I �P\[�@�s��(�ED�z���P��])8�G#��0B��[ى��X�II�q<��9�~[Z멜�Z�⊔IWU&A>�P~�#��dp<�?����7���c��'~���5 ��+$���lx@�M�dm��n<=e�dyX��?{�|Aef ,|n3�<~z�ƃ�uۧ�����P��Y,�ӥQ�*g�#먙R�\���;T��i,��[9Qi歉����c>]9�� ��"�c��P�� �Md?٥��If�ت�u��k��/����F��9�c*9��Ǎ:�ØF���z�n*�@|I�ށ9����N3{'��[�'ͬ�Ҳ4��#}��!�V� Fu��,�,mTIk���v C�7v���B�6k�T9��1�*l� '~��ƞF��lU��'�M ����][ΩũJ_�{�i�I�n��$���L�� j��O�dx�����kza۪��#�E��Cl����x˘�o�����V���ɞ�ljr��)�/,�߬h�L��#��^��L�ф�,íMƁe�̩�NB�L�����iL����q�}��(��q��6IçJ$�W�E$��:������=#����(�K�B����zђ <��K(�N�۫K�w��^O{!����)�H���>x�������lx�?>Պ�+�>�W���,Ly!_�D���Ō�l���Q�!�[ �S����J��1��Ɛ�Y}��b,+�Lo�x�ɓ)����=�y�oh�@�꥟/��I��ѭ=��P�y9��� �ۍYӘ�e+�p�Jnϱ?V\SO%�(�t� ���=?MR�[Ș�����d�/ ��n�l��B�7j� ��!�;ӥ�/�[-���A�>�dN�sLj ��,ɪv��=1c�.SQ�O3�U���ƀ�ܽ�E����������̻��9G�ϷD�7(�}��Ävӌ\�y�_0[w ���<΍>����a_��[0+�L��F.�޺��f�>oN�T����q;���y\��bՃ��y�jH�<|q-eɏ�_?_9+P���Hp$�����[ux�K w�Mw��N�ی'$Y2�=��q���KB��P��~������Yul:�[<����F1�2�O���5=d����]Y�sw:���Ϯ���E��j,_Q��X��z`H1,#II ��d�wr��P˂@�ZJV����y$�\y�{}��^~���[:N����ߌ�U�������O��d�����ؾe��${p>G��3c���Ė�lʌ�� ת��[��`ϱ�-W����dg�I��ig2��� ��}s ��ؤ(%#sS@���~���3�X�nRG�~\jc3�v��ӍL��M[JB�T��s3}��j�Nʖ��W����;7��ç?=X�F=-�=����q�ߚ���#���='�c��7���ڑW�I(O+=:uxq�������������e2�zi+�kuG�R��������0�&e�n���iT^J����~\jy���p'dtG��s����O��3����9* �b#Ɋ�� p������[Bws�T�>d4�ۧs���nv�n���U���_�~,�v����ƜJ1��s�� �QIz��)�(lv8M���U=�;����56��G���s#�K���MP�=��LvyGd��}�VwWBF�'�à �?MH�U�g2�� ����!�p�7Q��j��ڴ����=��j�u��� Jn�A s���uM������e��Ɔ�Ҕ�!)'��8Ϣ�ٔ��ޝ(��Vp���צ֖d=�IC�J�Ǡ{q������kԭ�߸���i��@K����u�|�p=..�*+����x�����z[Aqġ#s2a�Ɗ���RR�)*HRsi�~�a &f��M��P����-K�L@��Z��Xy�'x�{}��Zm+���:�)�) IJ�-i�u���� ���ܒH��'�L(7�y�GӜq���� j��� 6ߌg1�g�o���,kر���tY�?W,���p���e���f�OQS��!K�۟cҒA�|ս�j�>��=⬒��˧L[�� �߿2JaB~R��u�:��Q�] �0H~���]�7��Ƽ�I���(}��cq '�ήET���q�?f�ab���ӥvr� �)o��-Q��_'����ᴎo��K������;��V���o��%���~OK ����*��b�f:���-ťIR��`B�5!RB@���ï�� �u �̯e\�_U�_������� g�ES��3�������QT��a����x����U<~�c?�*�#]�MW,[8O�a�x��]�1bC|踤�P��lw5V%�)�{t�<��d��5���0i�XSU��m:��Z�┵�i�"��1�^B�-��P�hJ��&)O��*�D��c�W��vM��)����}���P��ܗ-q����\mmζZ-l@�}��a��E�6��F�@��&Sg@���ݚ�M����� ȹ 4����#p�\H����dYDo�H���"��\��..R�B�H�z_�/5˘����6��KhJR��P�mƶi�m���3�,#c�co��q�a)*Pt����R�m�k�7x�D�E�\Y�閣_X�<���~�)���c[[�BP����6�Yq���S��0����%_����;��Àv�~�| VS؇ ��'O0��F0��\���U�-�d@�����7�SJ*z��3n��y��P����O���������m�~�P�3|Y��ʉr#�C�<�G~�.,! ���bqx���h~0=��!ǫ�jy����l�O,�[B��~��|9��ٱ����Xly�#�i�B��g%�S��������tˋ���e���ې��\[d�t)��.+u�|1 ������#�~Oj����hS�%��i.�~X���I�H�m��0n���c�1uE�q��cF�RF�o���7� �O�ꮧ� ���ۛ{��ʛi5�rw?׌#Qn�TW��~?y$��m\�\o����%W� ?=>S�N@�� �Ʈ���R����N�)�r"C�:��:����� �����#��qb��Y�. �6[��2K����2u�Ǧ�HYR��Q�MV��� �G�$��Q+.>�����nNH��q�^��� ����q��mM��V��D�+�-�#*�U�̒ ���p욳��u:�������IB���m���PV@O���r[b= �� ��1U�E��_Nm�yKbN�O���U�}�the�`�|6֮P>�\2�P�V���I�D�i�P�O;�9�r�mAHG�W�S]��J*�_�G��+kP�2����Ka�Z���H�'K�x�W�MZ%�O�YD�Rc+o��?�q��Ghm��d�S�oh�\�D�|:W������UA�Qc yT�q������~^�H��/��#p�CZ���T�I�1�ӏT����4��"�ČZ�����}��`w�#�*,ʹ�� ��0�i��課�Om�*�da��^gJ݅{���l�e9uF#T�ֲ��̲�ٞC"�q���ߍ ոޑ�o#�XZTp����@ o�8��(jd��xw�]�,f���`~�|,s��^����f�1���t��|��m�򸄭/ctr��5s��7�9Q�4�H1꠲BB@l9@���C�����+�wp�xu�£Yc�9��?`@#�o�mH�s2��)�=��2�.�l����jg�9$�Y�S�%*L������R�Y������7Z���,*=�䷘$�������arm�o�ϰ���UW.|�r�uf����IGw�t����Zwo��~5 ��YյhO+=8fF�)�W�7�L9lM�̘·Y���֘YLf�큹�pRF���99.A �"wz��=E\Z���'a� 2��Ǚ�#;�'}�G���*��l��^"q��+2FQ� hj��kŦ��${���ޮ-�T�٭cf�|�3#~�RJ����t��$b�(R��(����r���dx� >U b�&9,>���%E\� Ά�e�$��'�q't��*�א���ެ�b��-|d���SB�O�O��$�R+�H�)�܎�K��1m`;�J�2�Y~9��O�g8=vqD`K[�F)k�[���1m޼c��n���]s�k�z$@��)!I �x՝"v��9=�ZA=`Ɠi �:�E��)`7��vI��}d�YI�_ �o�:ob���o ���3Q��&D&�2=�� �Ά��;>�h����y.*ⅥS������Ӭ�+q&����j|UƧ����}���J0��WW< ۋS�)jQR�j���Ư��rN)�Gű�4Ѷ(�S)Ǣ�8��i��W52���No˓� ۍ%�5brOn�L�;�n��\G����=�^U�dI���8$�&���h��'���+�(������cȁ߫k�l��S^���cƗjԌE�ꭔ��gF���Ȓ��@���}O���*;e�v�WV���YJ\�]X'5��ղ�k�F��b 6R�o՜m��i N�i����>J����?��lPm�U��}>_Z&�KK��q�r��I�D�Չ~�q�3fL�:S�e>���E���-G���{L�6p�e,8��������QI��h��a�Xa��U�A'���ʂ���s�+טIjP�-��y�8ۈZ?J$��W�P� ��R�s�]��|�l(�ԓ��sƊi��o(��S0��Y� 8�T97.�����WiL��c�~�dxc�E|�2!�X�K�Ƙਫ਼�$((�6�~|d9u+�qd�^3�89��Y�6L�.I�����?���iI�q���9�)O/뚅����O���X��X�V��ZF[�یgQ�L��K1���RҖr@v�#��X�l��F���Нy�S�8�7�kF!A��sM���^rkp�jP�DyS$N���q��nxҍ!U�f�!eh�i�2�m���`�Y�I�9r�6� �TF���C}/�y�^���Η���5d�'��9A-��J��>{�_l+�`��A���[�'��յ�ϛ#w:݅�%��X�}�&�PSt�Q�"�-��\縵�/����$Ɨh�Xb�*�y��BS����;W�ջ_mc�����vt?2}1�;qS�d�d~u:2k5�2�R�~�z+|HE!)�Ǟl��7`��0�<�,�2*���Hl-��x�^����'_TV�gZA�'j� ^�2Ϊ��N7t�����?w�� �x1��f��Iz�C-Ȗ��K�^q�;���-W�DvT�7��8�Z�������� hK�(P:��Q- �8�n�Z���܃e貾�<�1�YT<�,�����"�6{/ �?�͟��|1�:�#g��W�>$����d��J��d�B��=��jf[��%rE^��il:��B���x���Sּ�1հ��,�=��*�7 fcG��#q� �eh?��2�7�����,�!7x��6�n�LC�4x��},Geǝ�tC.��vS �F�43��zz\��;QYC,6����~;RYS/6���|2���5���v��T��i����������mlv��������&� �nRh^ejR�LG�f���? �ۉҬܦƩ��|��Ȱ����>3����!v��i�ʯ�>�v��オ�X3e���_1z�Kȗ\<������!�8���V��]��?b�k41�Re��T�q��mz��TiOʦ�Z��Xq���L������q"+���2ۨ��8}�&N7XU7Ap�d�X��~�׿��&4e�o�F��� �H����O���č�c�� 懴�6���͉��+)��v;j��ݷ�� �UV�� i��� j���Y9GdÒJ1��詞�����V?h��l����l�cGs�ځ�������y�Ac�����\V3�? �� ܙg�>qH�S,�E�W�[�㺨�uch�⍸�O�}���a��>�q�6�n6����N6�q������N ! 1AQaq�0@����"2BRb�#Pr���3C`��Scst���$4D���%Td�� ?���N����a��3��m���C���w��������xA�m�q�m���m������$����4n淿t'��C"w��zU=D�\R+w�p+Y�T�&�պ@��ƃ��3ޯ?�Aﶂ��aŘ���@-�����Q�=���9D��ռ�ѻ@��M�V��P��܅�G5�f�Y<�u=,EC)�<�Fy'�"�&�չ�X~f��l�KԆV��?�� �W�N����=(� �;���{�r����ٌ�Y���h{�١������jW����P���Tc�����X�K�r��}���w�R��%��?���E��m�� �Y�q|����\lEE4���r���}�lsI�Y������f�$�=�d�yO����p�����yBj8jU�o�/�S��?�U��*������ˍ�0������u�q�m [�?f����a�� )Q�>����6#������� ?����0UQ����,IX���(6ڵ[�DI�MNލ�c&���υ�j\��X�R|,4��� j������T�hA�e��^���d���b<����n�� �즇�=!���3�^�`j�h�ȓr��jẕ�c�,ٞX����-����a�ﶔ���#�$��]w�O��Ӫ�1y%��L�Y<�wg#�ǝ�̗`�x�xa�t�w��»1���o7o5��>�m뭛C���Uƃߜ}�C���y1Xνm�F8�jI���]����H���ۺиE@I�i;r�8ӭ����V�F�Շ| ��&?�3|x�B�MuS�Ge�=Ӕ�#BE5G�����Y!z��_e��q�р/W>|-�Ci߇�t�1ޯќd�R3�u��g�=0 5��[?�#͏��q�cf���H��{ ?u�=?�?ǯ���}Z��z���hmΔ�BFTW�����<�q�(v� ��!��z���iW]*�J�V�z��gX֧A�q�&��/w���u�gYӘa���; �i=����g:��?2�dž6�ى�k�4�>�Pxs����}������G�9��3 ���)gG�R<>r h�$��'nc�h�P��Bj��J�ҧH� -��N1���N��?��~��}-q!=��_2hc�M��l�vY%UE�@|�v����M2�.Y[|y�"Eï��K�ZF,�ɯ?,q�?v�M 80jx�"�;�9vk�����+ ֧�� �ȺU��?�%�vcV��mA�6��Qg^M����A}�3�nl� QRN�l8�kkn�'�����(��M�7m9و�q���%ޟ���*h$Zk"��$�9��: �?U8�Sl��,,|ɒ��xH(ѷ����Gn�/Q�4�P��G�%��Ա8�N��!� �&�7�;���eKM7�4��9R/%����l�c>�x;������>��C�:�����t��h?aKX�bhe�ᜋ^�$�Iհ �hr7%F$�E��Fd���t��5���+�(M6�t����Ü�UU|zW�=a�Ts�Tg������dqP�Q����b'�m���1{|Y����X�N��b �P~��F^F:����k6�"�j!�� �I�r�`��1&�-$�Bevk:y���#yw��I0��x��=D�4��tU���P�ZH��ڠ底taP��6����b>�xa����Q�#� WeF��ŮNj�p�J* mQ�N����*I�-*�ȩ�F�g�3 �5��V�ʊ�ɮ�a��5F���O@{���NX��?����H�]3��1�Ri_u��������ѕ�� ����0��� F��~��:60�p�͈�S��qX#a�5>���`�o&+�<2�D����: �������ڝ�$�nP���*)�N�|y�Ej�F�5ټ�e���ihy�Z �>���k�bH�a�v��h�-#���!�Po=@k̆IEN��@��}Ll?j�O������߭�ʞ���Q|A07x���wt!xf���I2?Z��<ץ�T���cU�j��]��陎Ltl �}5�ϓ��$�,��O�mˊ�;�@O��jE��j(�ا,��LX���LO���Ц�90�O �.����a��nA���7������j4 ��W��_ٓ���zW�jcB������y՗+EM�)d���N�g6�y1_x��p�$Lv:��9�"z��p���ʙ$��^��JԼ*�ϭ����o���=x�Lj�6�J��u82�A�H�3$�ٕ@�=Vv�]�'�qEz�;I˼��)��=��ɯ���x �/�W(V���p�����$ �m�������u�����񶤑Oqˎ�T����r��㠚x�sr�GC��byp�G��1ߠ�w e�8�$⿄����/�M{*}��W�]˷.�CK\�ުx���/$�WPw���r� |i���&�}�{�X� �>��$-��l���?-z���g����lΆ���(F���h�vS*���b���߲ڡn,|)mrH[���a�3�ר�[1��3o_�U�3�TC�$��(�=�)0�kgP���� ��u�^=��4 �WYCҸ:��vQ�ר�X�à��tk�m,�t*��^�,�}D*� �"(�I��9R����>`�`��[~Q]�#af��i6l��8���6�:,s�s�N6�j"�A4���IuQ��6E,�GnH��zS�HO�uk�5$�I�4��ؤ�Q9�@��C����wp�BGv[]�u�Ov���0I4���\��y�����Q�Ѹ��~>Z��8�T��a��q�ޣ;z��a���/��S��I:�ܫ_�|������>=Z����8:�S��U�I�J��"IY���8%b8���H��:�QO�6�;7�I�S��J��ҌAά3��>c���E+&jf$eC+�z�;��V����� �r���ʺ������my�e���aQ�f&��6�ND��.:��NT�vm�<- u���ǝ\MvZY�N�NT��-A�>jr!S��n�O 1�3�Ns�%�3D@���`������ܟ 1�^c<���� �a�ɽ�̲�Xë#�w�|y�cW�=�9I*H8�p�^(4���՗�k��arOcW�tO�\�ƍR��8����'�K���I�Q�����?5�>[�}��yU�ײ -h��=��% q�ThG�2�)���"ו3]�!kB��*p�FDl�A���,�eEi�H�f�Ps�����5�H:�Փ~�H�0Dت�D�I����h�F3�������c��2���E��9�H��5�zԑ�ʚ�i�X�=:m�xg�hd(�v����׊�9iS��O��d@0ڽ���:�p�5�h-��t�&���X�q�ӕ,��ie�|���7A�2���O%P��E��htj��Y1��w�Ѓ!����  ���� ࢽ��My�7�\�a�@�ţ�J �4�Ȼ�F�@o�̒?4�wx��)��]�P��~�����u�����5�����7X ��9��^ܩ�U;Iꭆ 5 �������eK2�7(�{|��Y׎ �V��\"���Z�1� Z�����}��(�Ǝ"�1S���_�vE30>���p;� ΝD��%x�W�?W?v����o�^V�i�d��r[��/&>�~`�9Wh��y�;���R��� ;;ɮT��?����r$�g1�K����A��C��c��K��l:�'��3 c�ﳯ*"t8�~l��)���m��+U,z��`(�>yJ�?����h>��]��v��ЍG*�{`��;y]��I�T� ;c��NU�fo¾h���/$���|NS���1�S�"�H��V���T���4��uhǜ�]�v;���5�͠x��'C\�SBpl���h}�N����� A�Bx���%��ޭ�l��/����T��w�ʽ]D�=����K���ž�r㻠l4�S�O?=�k �M:� ��c�C�a�#ha���)�ѐxc�s���gP�iG��{+���x���Q���I= �� z��ԫ+ �8"�k�ñ�j=|����c ��y��CF��/��*9ж�h{ �?4�o� ��k�m�Q�N�x��;�Y��4膚�a�w?�6�>e]�����Q�r�:����g�,i"�����ԩA�*M�<�G��b�if��l^M��5� �Ҩ�{����6J��ZJ�����P�*�����Y���ݛu�_4�9�I8�7���������,^ToR���m4�H��?�N�S�ѕw��/S��甍�@�9H�S�T��t�ƻ���ʒU��*{Xs�@����f�����֒Li�K{H�w^���������Ϥm�tq���s� ���ք��f:��o~s��g�r��ט� �S�ѱC�e]�x���a��) ���(b-$(�j>�7q�B?ӕ�F��hV25r[7 Y� }L�R��}����*sg+��x�r�2�U=�*'WS��ZDW]�WǞ�<��叓���{�$�9Ou4��y�90-�1�'*D`�c�^o?(�9��u���ݐ��'PI&� f�Jݮ�������:wS����jfP1F:X �H�9dԯ���˝[�_54 �}*;@�ܨ�� ð�yn�T���?�ןd�#���4rG�ͨ��H�1�|-#���Mr�S3��G�3�����)�.᧏3v�z֑��r����$G"�`j �1t��x0<Ɔ�Wh6�y�6��,œ�Ga��gA����y��b��)��h�D��ß�_�m��ü �gG;��e�v��ݝ�nQ� ��C����-�*��o���y�a��M��I�>�<���]obD��"�:���G�A��-\%LT�8���c�)��+y76���o�Q�#*{�(F�⽕�y����=���rW�\p���۩�c���A���^e6��K������ʐ�cVf5$�'->���ՉN"���F�"�UQ@�f��Gb~��#�&�M=��8�ט�JNu9��D��[̤�s�o�~������ G��9T�tW^g5y$b��Y'��س�Ǵ�=��U-2 #�MC�t(�i� �lj�@Q 5�̣i�*�O����s�x�K�f��}\��M{E�V�{�υ��Ƈ�����);�H����I��fe�Lȣr�2��>��W�I�Ȃ6������i��k�� �5�YOxȺ����>��Y�f5'��|��H+��98pj�n�.O�y�������jY��~��i�w'������l�;�s�2��Y��:'lg�ꥴ)o#'Sa�a�K��Z� �m��}�`169�n���"���x��I ��*+� }F<��cГ���F�P�������ֹ*�PqX�x۩��,� ��N�� �4<-����%����:��7����W���u�`����� $�?�I��&����o��o��`v�>��P��"��l���4��5'�Z�gE���8���?��[�X�7(��.Q�-��*���ތL@̲����v��.5���[��=�t\+�CNܛ��,g�SQnH����}*F�G16���&:�t��4ُ"A��̣��$�b �|����#rs��a�����T�� ]�<�j��BS�('$�ɻ� �wP;�/�n��?�ݜ��x�F��yUn�~mL*-�������Xf�wd^�a�}��f�,=t�׵i�.2/wpN�Ep8�OР���•��R�FJ� 55TZ��T �ɭ�<��]��/�0�r�@�f��V��V����Nz�G��^���7hZi����k��3�,kN�e|�vg�1{9]_i��X5y7� 8e]�U����'�-2,���e"����]ot�I��Y_��n�(JҼ��1�O ]bXc���Nu�No��pS���Q_���_�?i�~�x h5d'�(qw52] ��'ޤ�q��o1�R!���`ywy�A4u���h<קy���\[~�4�\ X�Wt/� 6�����n�F�a8��f���z �3$�t(���q��q�x��^�XWeN'p<-v�!�{�(>ӽDP7��ո0�y)�e$ٕv�Ih'Q�EA�m*�H��RI��=:��� ���4牢) �%_iN�ݧ�l]� �Nt���G��H�L��� ɱ�g<���1V�,�J~�ٹ�"K��Q�� 9�HS�9�?@��k����r�;we݁�]I�!{ �@�G�[�"��`���J:�n]�{�cA�E����V��ʆ���#��U9�6����j�#Y�m\��q�e4h�B�7��C�������d<�?J����1g:ٳ���=Y���D�p�ц� ׈ǔ��1�]26؜oS�'��9�V�FVu�P�h�9�xc�oq�X��p�o�5��Ա5$�9W�V(�[Ak�aY錎qf;�'�[�|���b�6�Ck��)��#a#a˙��8���=äh�4��2��C��4tm^ �n'c���]GQ$[Wҿ��i���vN�{Fu ��1�gx��1┷���N�m��{j-,��x�� Ūm�ЧS�[�s���Gna���䑴�� x�p 8<������97�Q���ϴ�v�aϚG��Rt�Һ׈�f^\r��WH�JU�7Z���y)�vg=����n��4�_)y��D'y�6�]�c�5̪�\� �PF�k����&�c;��cq�$~T�7j ���nç]�<�g ":�to�t}�159�<�/�8������m�b�K#g'I'.W�����6��I/��>v��\�MN��g���m�A�yQL�4u�Lj�j9��#44�t��l^�}L����n��R��!��t��±]��r��h6ٍ>�yҏ�N��fU�� ���� Fm@�8}�/u��jb9������he:A�y�ծw��GpΧh�5����l}�3p468��)U��d��c����;Us/�֔�YX�1�O2��uq�s��`hwg�r~�{ R��mhN��؎*q 42�*th��>�#���E����#��Hv�O����q�}�����6�e��\�,Wk�#���X��b>��p}�դ��3���T5��†��6��[��@�P�y*n��|'f�֧>�lư΂�̺����SU�'*�q�p�_S�����M�� '��c�6�����m�� ySʨ;M��r���Ƌ�m�Kxo,���Gm�P��A�G�:��i��w�9�}M(�^�V��$ǒ�ѽ�9���|���� �a����J�SQ�a���r�B;����}���ٻ֢�2�%U���c�#�g���N�a�ݕ�'�v�[�OY'��3L�3�;,p�]@�S��{ls��X�'���c�jw�k'a�.��}�}&�� �dP�*�bK=ɍ!����;3n�gΊU�ߴmt�'*{,=SzfD� A��ko~�G�aoq�_mi}#�m�������P�Xhύ����mxǍ�΂���巿zf��Q���c���|kc�����?���W��Y�$���_Lv����l߶��c���`?����l�j�ݲˏ!V��6����U�Ђ(A���4y)H���p�Z_�x��>���e��R��$�/�`^'3qˏ�-&Q�=?��CFVR �D�fV�9��{�8g�������n�h�(P"��6�[�D���< E�����~0<@�`�G�6����Hг�cc�� �c�K.5��D��d�B���`?�XQ��2��ٿyqo&+�1^� DW�0�ꊩ���G�#��Q�nL3��c���������/��x ��1�1[y�x�პCW��C�c�UĨ80�m�e�4.{�m��u���I=��f�����0QRls9���f���������9���~f�����Ǩ��a�"@�8���ȁ�Q����#c�ic������G��$���G���r/$W�(��W���V�"��m�7�[m�A�m����bo��D� j����۳� l���^�k�h׽����� ��#� iXn�v��eT�k�a�^Y�4�BN��ĕ��0 !01@Q"2AaPq3BR������?���@4�Q�����T3,���㺠�W�[=JK�Ϟ���2�r^7��vc�:�9 �E�ߴ�w�S#d���Ix��u��:��Hp��9E!�� V 2;73|F��9Y���*ʬ�F��D����u&���y؟��^EA��A��(ɩ���^��GV:ݜDy�`��Jr29ܾ�㝉��[���E;Fzx��YG��U�e�Y�C���� ����v-tx����I�sם�Ę�q��Eb�+P\ :>�i�C'�;�����k|z�رn�y]�#ǿb��Q��������w�����(�r|ӹs��[�D��2v-%��@;�8<a���[\o[ϧw��I!��*0�krs)�[�J9^��ʜ��p1)� "��/_>��o��<1����A�E�y^�C��`�x1'ܣn�p��s`l���fQ��):�l����b>�Me�jH^?�kl3(�z:���1ŠK&?Q�~�{�ٺ�h�y���/�[��V�|6��}�KbX����mn[-��7�5q�94�������dm���c^���h� X��5��<�eޘ>G���-�}�دB�ޟ� ��|�rt�M��V+�]�c?�-#ڛ��^ǂ}���Lkr���O��u�>�-D�ry� D?:ޞ�U��ǜ�7�V��?瓮�"�#���r��չģVR;�n���/_� ؉v�ݶe5d�b9��/O��009�G���5n�W����JpA�*�r9�>�1��.[t���s�F���nQ� V 77R�]�ɫ8����_0<՜�IF�u(v��4��F�k�3��E)��N:��yڮe��P�`�1}�$WS��J�SQ�N�j�ٺ��޵�#l���ј(�5=��5�lǏmoW�v-�1����v,W�mn��߀$x�<����v�j(����c]��@#��1������Ǔ���o'��u+����;G�#�޸��v-lη��/(`i⣍Pm^���ԯ̾9Z��F��������n��1��� ��]�[��)�'������:�֪�W��FC����� �B9،!?���]��V��A�Վ�M��b�w��G F>_DȬ0¤�#�QR�[V��kz���m�w�"��9ZG�7'[��=�Q����j8R?�zf�\a�=��O�U����*oB�A�|G���2�54 �p��.w7� �� ��&������ξxGHp� B%��$g�����t�Џ򤵍z���HN�u�Я�-�'4��0��;_��3 !01"@AQa2Pq#3BR������?��ʩca��en��^��8���<�u#��m*08r��y�N"�<�Ѳ0��@\�p��� �����Kv�D��J8�Fҽ� �f�Y��-m�ybX�NP����}�!*8t(�OqѢ��Q�wW�K��ZD��Δ^e��!� ��B�K��p~�����e*l}z#9ң�k���q#�Ft�o��S�R����-�w�!�S���Ӥß|M�l޶V��!eˈ�8Y���c�ЮM2��tk���� ������J�fS����Ö*i/2�����n]�k�\���|4yX�8��U�P.���Ы[���l��@"�t�<������5�lF���vU�����W��W��;�b�cД^6[#7@vU�xgZv��F�6��Q,K�v��� �+Ъ��n��Ǣ��Ft���8��0��c�@�!�Zq s�v�t�;#](B��-�nῃ~���3g������5�J�%���O������n�kB�ĺ�.r��+���#�N$?�q�/�s�6��p��a����a��J/��M�8��6�ܰ"�*������ɗud"\w���aT(����[��F��U՛����RT�b���n�*��6���O��SJ�.�ij<�v�MT��R\c��5l�sZB>F��<7�;EA��{��E���Ö��1U/�#��d1�a�n.1ě����0�ʾR�h��|�R��Ao�3�m3 ��%�� ���28Q� ��y��φ���H�To�7�lW>����#i`�q���c����a��� �m,B�-j����݋�'mR1Ήt�>��V��p���s�0IbI�C.���1R�ea�����]H�6����������4B>��o��](��$B���m�����a�!=��?�B� K�Ǿ+�Ծ"�n���K��*��+��[T#�{E�J�S����Q�����s�5�:�U�\wĐ�f�3����܆&�)����I���Ԇw��E T�lrTf6Q|R�h:��[K�� �z��c֧�G�C��%\��_�a�84��HcO�bi��ؖV��7H �)*ģK~Xhչ0��4?�0��� �E<���}3���#���u�?�� ��|g�S�6ꊤ�|�I#Hڛ� �ա��w�X��9��7���Ŀ%�SL��y6č��|�F�a 8���b��$�sק�h���b9RAu7�˨p�Č�_\*w��묦��F ����4D~�f����|(�"m���NK��i�S�>�$d7SlA��/�²����SL��|6N�}���S�˯���g��]6��; �#�.��<���q'Q�1|KQ$�����񛩶"�$r�b:���N8�w@��8$�� �AjfG|~�9F ���Y��ʺ��Bwؒ������M:I岎�G��`s�YV5����6��A �b:�W���G�q%l�����F��H���7�������Fsv7��k�� 403WebShell
403Webshell
Server IP : 51.161.54.47  /  Your IP : 216.73.216.143
Web Server : Apache/2.4.68 (Unix) OpenSSL/1.1.1k
System : Linux host.ditinformatica.ar 4.18.0-553.153.1.el8_10.x86_64 #1 SMP Thu Aug 6 00:53:12 EDT 2026 x86_64
User : kalaycom ( 1021)
PHP Version : 7.4.33
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /usr/share/nmap/nselib/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /usr/share/nmap/nselib/dns.lua
---
-- Simple DNS library supporting packet creation, encoding, decoding,
-- and querying.
--
-- The most common interface to this module are the <code>query</code> and
-- <code>reverse</code> functions. <code>query</code> performs a DNS query,
-- and <code>reverse</code> prepares an ip address to have a reverse query
-- performed.
--
-- <code>query</code> takes two options - a domain name to look up and an
-- optional table of options. For more information on the options table,
-- see the documentation for <code>query</code>.
--
-- Example usage:
-- <code>
--  -- After this call, <code>status</code> is <code>true</code> and <code>result</code> is <code>"72.14.204.104"</code>
--  local status, result = dns.query('www.google.ca')
--
--  -- After this call, <code>status</code> is <code>false</code> and <code>result</code> is <code>"No such name"</code>
--  local status, result = dns.query('www.google.abc')
--
--  -- After this call, <code>status</code> is <code>true</code> and <code>result</code> is the table <code>{"72.14.204.103", "72.14.204.104", "72.14.204.147", "72.14.204.99"}</code>
--  local status, result = dns.query('www.google.ca', {retAll=true})
--
--  -- After this call, <code>status</code> is <code>true</code> and <code>result</code> is the <code>"2001:19f0:0:0:0:dead:beef:cafe"</code>
--  local status, result = dns.query('irc.ipv6.efnet.org', {dtype='AAAA'})
--</code>
--
--
-- @copyright Same as Nmap--See https://nmap.org/book/man-legal.html


local coroutine = require "coroutine"
local ipOps = require "ipOps"
local nmap = require "nmap"
local stdnse = require "stdnse"
local string = require "string"
local stringaux = require "stringaux"
local table = require "table"
local base32 = require "base32"
local unittest = require "unittest"
_ENV = stdnse.module("dns", stdnse.seeall)

get_servers = nmap.get_dns_servers

---
-- Table of DNS resource types.
-- @name types
-- @class table
types = {
  A = 1,
  NS = 2,
  SOA = 6,
  CNAME = 5,
  PTR = 12,
  HINFO = 13,
  MX = 15,
  TXT = 16,
  AAAA = 28,
  SRV = 33,
  OPT = 41,
  SSHFP = 44,
  NSEC = 47,
  NSEC3 = 50,
  AXFR = 252,
  ANY = 255
}

CLASS = {
  IN = 1,
  CH = 3,
  ANY = 255
}


---
-- Repeatedly sends UDP packets to host, waiting for an answer.
-- @param data Data to be sent.
-- @param host Host to connect to.
-- @param port Port to connect to.
-- @param timeout Number of ms to wait for a response.
-- @param cnt Number of tries.
-- @param multiple If true, keep reading multiple responses until timeout.
-- @return Status (true or false).
-- @return Response (if status is true).
local function sendPacketsUDP(data, host, port, timeout, cnt, multiple)
  local socket = nmap.new_socket("udp")
  local responses = {}

  socket:set_timeout(timeout)

  if ( not(multiple) ) then
    socket:connect( host, port, "udp" )
  end

  for i = 1, cnt do
    local status, err

    if ( multiple ) then
      status, err = socket:sendto(host, port, data)
    else
      status, err = socket:send(data)
    end

    if (not(status)) then return false, err end

    local response

    if ( multiple ) then
      while(true) do
        status, response = socket:receive()
        if( not(status) ) then break end

        local status, _, _, ip, _ = socket:get_info()
        table.insert(responses, { data = response, peer = ip } )
      end
    else
      status, response = socket:receive()
      if ( status ) then
        local status, _, _, ip, _ = socket:get_info()
        table.insert(responses, { data = response, peer = ip } )
      end
    end

    if (#responses>0) then
      socket:close()
      return true, responses
    end
  end
  socket:close()
  return false
end

---
-- Send TCP DNS query
-- @param data Data to be sent.
-- @param host Host to connect to.
-- @param port Port to connect to.
-- @param timeout Number of ms to wait for a response.
-- @return Status (true or false).
-- @return Response (if status is true).
local function sendPacketsTCP(data, host, port, timeout)
  local socket = nmap.new_socket()
  local response
  local responses = {}
  socket:set_timeout(timeout)
  socket:connect(host, port)
  -- add payload size we are assuming a minimum size here of 256?
  local send_data = '\000' .. string.char(#data) .. data
  socket:send(send_data)
  local response = ''
  local got_response = false
  while true do
    local status, recv_data = socket:receive_bytes(1)
    if not status then break end
    got_response = true
    response = response .. recv_data
  end
  local status, _, _, ip, _ = socket:get_info()
  socket:close()
  if not got_response then
    return false
  end
  -- remove payload size
  table.insert(responses, { data = string.sub(response,3), peer = ip } )
  return true, responses
end

---
-- Call appropriate protocol handler
-- @param data Data to be sent.
-- @param host Host to connect to.
-- @param port Port to connect to.
-- @param timeout Number of ms to wait for a response.
-- @param cnt Number of tries.
-- @param multiple If true, keep reading multiple responses until timeout.
-- @return Status (true or false).
local function sendPackets(data, host, port, timeout, cnt, multiple, proto)
  if proto == nil or proto == 'udp' then
    return sendPacketsUDP(data, host, port, timeout, cnt, multiple)
  else
    return sendPacketsTCP(data, host, port, timeout)
  end
end

---
-- Checks if a DNS response packet contains a useful answer.
-- @param rPkt Decoded DNS response packet.
-- @return True if useful, false if not.
local function gotAnswer(rPkt)
  -- have we even got answers?
  if #rPkt.answers > 0 then

    -- some MDNS implementation incorrectly return an empty question section
    -- if this is the case return true
    if rPkt.questions[1] == nil then
      return true
    end

    -- are those answers not just cnames?
    if rPkt.questions[1].dtype == types.A then
      for _, v in ipairs(rPkt.answers) do
        -- if at least one answer is an A record, it's an answer
        if v.dtype == types.A then
          return true
        end
      end
      -- if none was an A record, it's not really an answer
      return false
    else -- there was no A request, CNAMEs are not of interest
      return true
    end
    -- no such name is the answer
  elseif rPkt.flags.RC3 and rPkt.flags.RC4 then
    return true
    -- really no answer
  else
    return false
  end
end


---
-- Tries to find the next nameserver with authority to get a result for
-- query.
-- @param rPkt Decoded DNS response packet
-- @return String or table of next server(s) to query, or false.
local function getAuthDns(rPkt)
  if #rPkt.auth == 0 then
    if #rPkt.answers == 0 then
      return false
    else
      if rPkt.answers[1].dtype == types.CNAME then
        return {cname = rPkt.answers[1].domain}
      end
    end
  end
  if rPkt.auth[1].dtype == types.NS then
    if #rPkt.add > 0 then
      local hosts = {}
      for _, v in ipairs(rPkt.add) do
        if v.dtype == types.A then
          table.insert(hosts, v.ip)
        end
      end
      if #hosts > 0 then return hosts end
    end
    local status, next = query(rPkt.auth[1].domain, {dtype = "A" })
    return next
  end
  return false
end

local function processResponse( response, dname, dtype, options )

  local rPkt = decode(response)
  -- is it a real answer?
  if gotAnswer(rPkt) then
    if (options.retPkt) then
      return true, rPkt
    else
      return findNiceAnswer(dtype, rPkt, options.retAll)
    end
  elseif ( not(options.noauth) ) then -- if not, ask the next server in authority

    local next_server = getAuthDns(rPkt)

    -- if we got a CNAME, ask for the CNAME
    if type(next_server) == 'table' and next_server.cname then
      options.tries = options.tries - 1
      return query(next_server.cname, options)
    end

    -- only ask next server in authority, if
    -- we got an auth dns and
    -- it isn't the one we just asked
    if next_server and next_server ~= options.host and options.tries > 1 then
      options.host = next_server
      options.tries = options.tries - 1
      return query(dname, options)
    end
  elseif ( options.retPkt ) then
    return true, rPkt
  end

  -- nothing worked
  stdnse.debug1("dns.query() failed to resolve the requested query%s%s", dname and ": " or ".", dname or "")
  return false, "No Answers"

end

---
-- Query DNS servers for a DNS record.
-- @param dname Desired domain name entry.
-- @param options A table containing any of the following fields:
-- * <code>dtype</code>: Desired DNS record type (default: <code>"A"</code>).
-- * <code>host</code>: DNS server to be queried (default: DNS servers known to Nmap).
-- * <code>port</code>: Port of DNS server to connect to (default: <code>53</code>).
-- * <code>tries</code>: How often should <code>query</code> try to contact another server (for non-recursive queries).
-- * <code>retAll</code>: Return all answers, not just the first.
-- * <code>retPkt</code>: Return the packet instead of using the answer-fetching mechanism.
-- * <code>norecurse</code>: If true, do not set the recursion (RD) flag.
-- * <code>noauth</code>: If true, do not try to find authoritative server
-- * <code>multiple</code>: If true, expects multiple hosts to respond to multicast request
-- * <code>flags</code>: numeric value to set flags in the DNS query to a specific value
-- * <code>id</code>: numeric value to use for the DNS transaction id
-- * <code>nsid</code>: If true, queries the server for the nameserver identifier (RFC 5001)
-- * <code>subnet</code>: table, if set perform a edns-client-subnet lookup. The table should contain the fields:
--                        <code>family</code> - IPv4: "inet" or 1 (default), IPv6: "inet6" or 2
--                        <code>address</code> - string containing the originating subnet IP address
--                        <code>mask</code> - number containing the number of subnet bits
-- @return <code>true</code> if a dns response was received and contained an answer of the requested type,
--  or the decoded dns response was requested (retPkt) and is being returned - or <code>false</code> otherwise.
-- @return String answer of the requested type, table of answers or a String error message of one of the following:
--  "No Such Name", "No Servers", "No Answers", "Unable to handle response"
function query(dname, options)
  if not options then options = {} end

  local dtype, host, port, proto = options.dtype, options.host, options.port, options.proto
  if proto == nil then proto = 'udp' end
  if port == nil then port = '53' end

  local class = options.class or CLASS.IN
  if not options.tries then options.tries = 10 end -- don't get into an infinite loop

  if not options.sendCount then options.sendCount = 2 end

  if type( options.timeout ) ~= "number" then options.timeout = get_default_timeout() end

  if type(dtype) == "string" then
    dtype = types[dtype]
  end
  if not dtype then dtype = types.A end

  local srv
  local srvI = 1
  if not port then port = 53 end
  if not host then
    srv = get_servers()
    if srv and srv[1] then
      host = srv[1]
    else
      return false, "No Servers"
    end
  elseif type(host) == "table" then
    srv = host
    host = srv[1]
  end

  local pkt = newPacket()
  addQuestion(pkt, dname, dtype, class)
  if options.norecurse then pkt.flags.RD = false end

  local dnssec = {}
  if ( options.dnssec ) then
    dnssec = { DO = true }
  end

  if ( options.nsid ) then
    addNSID(pkt, dnssec)
  elseif ( options.subnet ) then
    addClientSubnet(pkt, dnssec, options.subnet )
  elseif ( dnssec.DO ) then
    addOPT(pkt, {DO = true})
  end

  if ( options.flags ) then pkt.flags.raw = options.flags end
  if ( options.id ) then pkt.id = options.id end

  local data = encode(pkt)

  local status, response = sendPackets(data, host, port, options.timeout, options.sendCount, options.multiple, proto)


  -- if working with know nameservers, try the others
  while((not status) and srv and srvI < #srv) do
    srvI = srvI + 1
    host = srv[srvI]
    status, response = sendPackets(data, host, port, options.timeout, options.sendCount)
  end

  -- if we got any response:
  if status then
    if ( options.multiple ) then
      local multiresponse = {}
      for _, r in ipairs( response ) do
        local status, presponse = processResponse( r.data, dname, dtype, options )
        if( status ) then
          table.insert( multiresponse, { ['output']=presponse, ['peer']=r.peer } )
        end
      end
      return true, multiresponse
    else
      return processResponse( response[1].data, dname, dtype, options)
    end
  else
    stdnse.debug1("dns.query() got zero responses attempting to resolve query%s%s", dname and ": " or ".", dname or "")
    return false, "No Answers"
  end
end


---
-- Formats an IP address for reverse lookup.
-- @param ip IP address string.
-- @return "Domain"-style representation of IP as subdomain of in-addr.arpa or
-- ip6.arpa.
function reverse(ip)
  ip = ipOps.expand_ip(ip)
  if type(ip) ~= "string" then return nil end
  local delim = "%."
  local arpa = ".in-addr.arpa"
  if ip:match(":") then
    delim = ":"
    arpa = ".ip6.arpa"
  end
  local ipParts = stringaux.strsplit(delim, ip)
  if #ipParts == 8 then
    -- padding
    local mask = "0000"
    for i, part in ipairs(ipParts) do
      ipParts[i] = mask:sub(1, #mask - #part) .. part
    end
    -- 32 parts from 8
    local temp = {}
    for i, hdt in ipairs(ipParts) do
      for part in hdt:gmatch("%x") do
        temp[#temp+1] = part
      end
    end
    ipParts = temp
  end
  local ipReverse = {}
  for i = #ipParts, 1, -1 do
    table.insert(ipReverse, ipParts[i])
  end
  return table.concat(ipReverse, ".") .. arpa
end

-- Table for answer fetching functions.
local answerFetcher = {}

-- Answer fetcher for TXT records.
-- @param dec Decoded DNS response.
-- @param retAll If true, return all entries, not just the first.
-- @return True if one or more answers of the required type were found - otherwise false.
-- @return String first dns TXT record or Table of TXT records or String Error message.
answerFetcher[types.TXT] = function(dec, retAll)
  local answers = {}
  if not retAll and dec.answers[1].data then
    return true, string.sub(dec.answers[1].data, 2)
  elseif not retAll then
    stdnse.debug1("dns.answerFetcher found no records of the required type: TXT")
    return false, "No Answers"
  else
    for _, v in ipairs(dec.answers) do
      if v.TXT and v.TXT.text then
        for _, v in ipairs( v.TXT.text ) do
          table.insert(answers, v)
        end
      end
    end
  end
  if #answers == 0 then
    stdnse.debug1("dns.answerFetcher found no records of the required type: TXT")
    return false, "No Answers"
  end
  return true, answers
end

-- Answer fetcher for A records
-- @param dec Decoded DNS response.
-- @param retAll If true, return all entries, not just the first.
-- @return True if one or more answers of the required type were found - otherwise false.
-- @return String first dns A record or Table of A records or String Error message.
answerFetcher[types.A] = function(dec, retAll)
  local answers = {}
  for _, ans in ipairs(dec.answers) do
    if ans.dtype == types.A then
      if not retAll then
        return true, ans.ip
      end
      table.insert(answers, ans.ip)
    end
  end
  if not retAll or #answers == 0 then
    stdnse.debug1("dns.answerFetcher found no records of the required type: A")
    return false, "No Answers"
  end
  return true, answers
end


-- Answer fetcher for CNAME records.
-- @param dec Decoded DNS response.
-- @param retAll If true, return all entries, not just the first.
-- @return True if one or more answers of the required type were found - otherwise false.
-- @return String first Domain entry or Table of domain entries or String Error message.
answerFetcher[types.CNAME] = function(dec, retAll)
  local answers = {}
  if not retAll and dec.answers[1].domain then
    return true, dec.answers[1].domain
  elseif not retAll then
    stdnse.debug1("dns.answerFetcher found no records of the required type: NS, PTR or CNAME")
    return false, "No Answers"
  else
    for _, v in ipairs(dec.answers) do
      if v.domain then table.insert(answers, v.domain) end
    end
  end
  if #answers == 0 then
    stdnse.debug1("dns.answerFetcher found no records of the required type: NS, PTR or CNAME")
    return false, "No Answers"
  end
  return true, answers
end

-- Answer fetcher for MX records.
-- @param dec Decoded DNS response.
-- @param retAll If true, return all entries, not just the first.
-- @return True if one or more answers of the required type were found - otherwise false.
-- @return String first dns MX record or Table of MX records or String Error message.
--  Note that the format of a returned MX answer is "preference:hostname:IPaddress" where zero
--  or more IP addresses may be present.
answerFetcher[types.MX] = function(dec, retAll)
  local mx, ip, answers = {}, {}, {}
  for _, ans in ipairs(dec.answers) do
    if ans.MX then mx[#mx+1] = ans.MX end
    if not retAll then break end
  end
  if #mx == 0 then
    stdnse.debug1("dns.answerFetcher found no records of the required type: MX")
    return false, "No Answers"
  end
  for _, add in ipairs(dec.add) do
    if ip[add.dname] then table.insert(ip[add.dname], add.ip)
    else ip[add.dname] = {add.ip} end
  end
  for _, mxrec in ipairs(mx) do
    if ip[mxrec.server] then
      table.insert( answers, ("%s:%s:%s"):format(mxrec.pref or "-", mxrec.server or "-", table.concat(ip[mxrec.server], ":")) )
      if not retAll then return true, answers[1] end
    else
      -- no IP ?
      table.insert( answers, ("%s:%s"):format(mxrec.pref or "-", mxrec.server or "-") )
      if not retAll then return true, answers[1] end
    end
  end
  return true, answers
end

-- Answer fetcher for SRV records.
-- @param dec Decoded DNS response.
-- @param retAll If true, return all entries, not just the first.
-- @return True if one or more answers of the required type were found - otherwise false.
-- @return String first dns SRV record or Table of SRV records or String Error message.
--  Note that the format of a returned SRV answer is "priority:weight:port:target" where zero
--  or more IP addresses may be present.
answerFetcher[types.SRV] = function(dec, retAll)
  local srv, ip, answers = {}, {}, {}
  for _, ans in ipairs(dec.answers) do
    if ans.dtype == types.SRV then
      if not retAll then
        return true, ("%s:%s:%s:%s"):format( ans.SRV.prio, ans.SRV.weight, ans.SRV.port, ans.SRV.target )
      end
      table.insert( answers, ("%s:%s:%s:%s"):format( ans.SRV.prio, ans.SRV.weight, ans.SRV.port, ans.SRV.target ) )
    end
  end
  if #answers == 0 then
    stdnse.debug1("dns.answerFetcher found no records of the required type: SRV")
    return false, "No Answers"
  end

  return true, answers
end

-- Answer fetcher for NSEC records.
-- @param dec Decoded DNS response.
-- @param retAll If true, return all entries, not just the first.
-- @return True if one or more answers of the required type were found - otherwise false.
-- @return String first dns NSEC record or Table of NSEC records or String Error message.
--  Note that the format of a returned NSEC answer is "name:dname:types".
answerFetcher[types.NSEC] = function(dec, retAll)
  local nsec, answers = {}, {}
  for _, auth in ipairs(dec.auth) do
    if auth.NSEC then nsec[#nsec+1] = auth.NSEC end
    if not retAll then break end
  end
  if #nsec == 0 then
    stdnse.debug1("dns.answerFetcher found no records of the required type: NSEC")
    return false, "No Answers"
  end
  for _, nsecrec in ipairs(nsec) do
    table.insert( answers, ("%s:%s:%s"):format(nsecrec.name or "-", nsecrec.dname or "-", table.concat(nsecrec.types, ":") or "-"))
  end
  if not retAll then return true, answers[1] end
  return true, answers
end

-- Answer fetcher for NS records.
-- @name answerFetcher[types.NS]
-- @class function
-- @param dec Decoded DNS response.
-- @return True if one or more answers of the required type were found - otherwise false.
-- @return String first Domain entry or Table of domain entries or String Error message.
answerFetcher[types.NS] = answerFetcher[types.CNAME]

-- Answer fetcher for PTR records.
-- @name answerFetcher[types.PTR]
-- @class function
-- @param dec Decoded DNS response.
-- @param retAll If true, return all entries, not just the first.
-- @return True if one or more answers of the required type were found - otherwise false.
-- @return String first Domain entry or Table of domain entries or String Error message.
answerFetcher[types.PTR] = answerFetcher[types.CNAME]

-- Answer fetcher for AAAA records.
-- @param dec Decoded DNS response.
-- @param retAll If true, return all entries, not just the first.
-- @return True if one or more answers of the required type were found - otherwise false.
-- @return String first dns AAAA record or Table of AAAA records or String Error message.
answerFetcher[types.AAAA] = function(dec, retAll)
  local answers = {}
  for _, ans in ipairs(dec.answers) do
    if ans.dtype == types.AAAA then
      if not retAll then
        return true, ans.ipv6
      end
      table.insert(answers, ans.ipv6)
    end
  end
  if not retAll or #answers == 0 then
    stdnse.debug1("dns.answerFetcher found no records of the required type: AAAA")
    return false, "No Answers"
  end
  return true, answers
end


---Calls the answer fetcher for <code>dtype</code> or returns an error code in
-- case of a "no such name" error.
--
-- @param dtype DNS resource record type.
-- @param dec Decoded DNS response.
-- @param retAll If true, return all entries, not just the first.
-- @return True if one or more answers of the required type were found - otherwise false.
-- @return Answer according to the answer fetcher for <code>dtype</code> or an Error message.
function findNiceAnswer(dtype, dec, retAll)
  if (#dec.answers > 0) then
    if answerFetcher[dtype] then
      return answerFetcher[dtype](dec, retAll)
    else
      stdnse.debug1("dns.findNiceAnswer() does not have an answerFetcher for dtype %s", tostring(dtype))
      return false, "Unable to handle response"
    end
  elseif (dec.flags.RC3 and dec.flags.RC4) then
    return false, "No Such Name"
  else
    stdnse.debug1("dns.findNiceAnswer() found zero answers in a response, but got an unexpected flags.replycode")
    return false, "No Answers"
  end
end

-- Table for additional fetching functions.
-- Some servers return their answers in the additional section. The
-- findNiceAdditional function with its relevant additionalFetcher functions
-- addresses this. This unfortunately involved some code duplication (because
-- of current design of the dns library) from the answerFetchers to the
-- additionalFetchers.
local additionalFetcher = {}

-- Additional fetcher for TXT records.
-- @param dec Decoded DNS response.
-- @param retAll If true, return all entries, not just the first.
-- @return True if one or more answers of the required type were found - otherwise false.
-- @return String first dns TXT record or Table of TXT records or String Error message.
additionalFetcher[types.TXT] = function(dec, retAll)
  local answers = {}
  if not retAll and dec.add[1].data then
    return true, string.sub(dec.add[1].data, 2)
  elseif not retAll then
    stdnse.debug1("dns.additionalFetcher found no records of the required type: TXT")
    return false, "No Answers"
  else
    for _, v in ipairs(dec.add) do
      if v.TXT and v.TXT.text then
        for _, v in ipairs( v.TXT.text ) do
          table.insert(answers, v)
        end
      end
    end
  end
  if #answers == 0 then
    stdnse.debug1("dns.answerFetcher found no records of the required type: TXT")
    return false, "No Answers"
  end
  return true, answers
end

-- Additional fetcher for A records
-- @param dec Decoded DNS response.
-- @param retAll If true, return all entries, not just the first.
-- @return True if one or more answers of the required type were found - otherwise false.
-- @return String first dns A record or Table of A records or String Error message.
additionalFetcher[types.A] = function(dec, retAll)
  local answers = {}
  for _, ans in ipairs(dec.add) do
    if ans.dtype == types.A then
      if not retAll then
        return true, ans.ip
      end
      table.insert(answers, ans.ip)
    end
  end
  if not retAll or #answers == 0 then
    stdnse.debug1("dns.answerFetcher found no records of the required type: A")
    return false, "No Answers"
  end
  return true, answers
end


-- Additional fetcher for SRV records.
-- @param dec Decoded DNS response.
-- @param retAll If true, return all entries, not just the first.
-- @return True if one or more answers of the required type were found - otherwise false.
-- @return String first dns SRV record or Table of SRV records or String Error message.
--  Note that the format of a returned SRV answer is "priority:weight:port:target" where zero
--  or more IP addresses may be present.
additionalFetcher[types.SRV] = function(dec, retAll)
  local srv, ip, answers = {}, {}, {}
  for _, ans in ipairs(dec.add) do
    if ans.dtype == types.SRV then
      if not retAll then
        return true, ("%s:%s:%s:%s"):format( ans.SRV.prio, ans.SRV.weight, ans.SRV.port, ans.SRV.target )
      end
      table.insert( answers, ("%s:%s:%s:%s"):format( ans.SRV.prio, ans.SRV.weight, ans.SRV.port, ans.SRV.target ) )
    end
  end
  if #answers == 0 then
    stdnse.debug1("dns.answerFetcher found no records of the required type: SRV")
    return false, "No Answers"
  end

  return true, answers
end


-- Additional fetcher for AAAA records.
-- @param dec Decoded DNS response.
-- @param retAll If true, return all entries, not just the first.
-- @return True if one or more answers of the required type were found - otherwise false.
-- @return String first dns AAAA record or Table of AAAA records or String Error message.
additionalFetcher[types.AAAA] = function(dec, retAll)
  local answers = {}
  for _, ans in ipairs(dec.add) do
    if ans.dtype == types.AAAA then
      if not retAll then
        return true, ans.ipv6
      end
      table.insert(answers, ans.ipv6)
    end
  end
  if not retAll or #answers == 0 then
    stdnse.debug1("dns.answerFetcher found no records of the required type: AAAA")
    return false, "No Answers"
  end
  return true, answers
end

---
-- Calls the answer fetcher for <code>dtype</code> or returns an error code in
-- case of a "no such name" error.
-- @param dtype DNS resource record type.
-- @param dec Decoded DNS response.
-- @param retAll If true, return all entries, not just the first.
-- @return True if one or more answers of the required type were found - otherwise false.
-- @return Answer according to the answer fetcher for <code>dtype</code> or an Error message.
function findNiceAdditional(dtype, dec, retAll)
  if (#dec.add > 0) then
    if additionalFetcher[dtype] then
      return additionalFetcher[dtype](dec, retAll)
    else
      stdnse.debug1("dns.findNiceAdditional() does not have an additionalFetcher for dtype %s",
      (type(dtype) == 'string' and dtype) or type(dtype) or "nil")
      return false, "Unable to handle response"
    end
  elseif (dec.flags.RC3 and dec.flags.RC4) then
    return false, "No Such Name"
  else
    stdnse.debug1("dns.findNiceAdditional() found zero answers in a response, but got an unexpected flags.replycode")
    return false, "No Answers"
  end
end

--
-- Encodes a FQDN
-- @param fqdn containing the fully qualified domain name
-- @return encQ containing the encoded value
local function encodeFQDN(fqdn)
  if ( not(fqdn) or #fqdn == 0 ) then return "\0" end

  local encQ = {}
  for part in string.gmatch(fqdn, "[^%.]+") do
    encQ[#encQ+1] = string.pack("s1", part)
  end
  encQ[#encQ+1] = "\0"
  return table.concat(encQ)
end

---
-- Encodes the question part of a DNS request.
-- @param questions Table of questions.
-- @return Encoded question string.
local function encodeQuestions(questions)
  if type(questions) ~= "table" then return nil end
  local encQ = {}
  for _, v in ipairs(questions) do
    encQ[#encQ+1] = encodeFQDN(v.dname)
    encQ[#encQ+1] = string.pack(">I2I2", v.dtype, v.class)
  end
  return table.concat(encQ)
end

---
-- Encodes the zone part of a DNS request.
-- @param questions Table of questions.
-- @return Encoded question string.
local function encodeZones(zones)
  return encodeQuestions(zones)
end

local function encodeUpdates(updates)
  if type(updates) ~= "table" then return nil end
  local encQ = {}
  for _, v in ipairs(updates) do
    encQ[#encQ+1] = encodeFQDN(v.dname)
    encQ[#encQ+1] = string.pack(">I2I2I4s2", v.dtype, v.class, v.ttl, v.data)
  end
  return table.concat(encQ)
end

---
-- Encodes the additional part of a DNS request.
-- @param additional Table of additional records. Each must have the keys
-- <code>type</code>, <code>class</code>, <code>ttl</code>,
-- and <code>rdata</code>.
-- @return Encoded additional string.
local function encodeAdditional(additional)
  if type(additional) ~= "table" then return nil end
  local encA = {}
  for _, v in ipairs(additional) do
    encA[#encA+1] = string.pack(">xI2I2I4s2",  v.type, v.class, v.ttl, v.rdata)
  end
  return table.concat(encA)
end

---
-- Encodes DNS flags to a binary digit string.
-- @param flags Flag table, each entry representing a flag (QR, OCx, AA, TC, RD,
-- RA, RCx).
-- @return Binary digit string representing flags.
local function encodeFlags(flags)
  if type(flags) == "number" then return flags end
  if type(flags) ~= "table" then return nil end
  local fb = 0
  if flags.QR  then fb = fb|0x8000 end
  if flags.OC1 then fb = fb|0x4000 end
  if flags.OC2 then fb = fb|0x2000 end
  if flags.OC3 then fb = fb|0x1000 end
  if flags.OC4 then fb = fb|0x0800 end
  if flags.AA  then fb = fb|0x0400 end
  if flags.TC  then fb = fb|0x0200 end
  if flags.RD  then fb = fb|0x0100 end
  if flags.RA  then fb = fb|0x0080 end
  if flags.RC1 then fb = fb|0x0008 end
  if flags.RC2 then fb = fb|0x0004 end
  if flags.RC3 then fb = fb|0x0002 end
  if flags.RC4 then fb = fb|0x0001 end
  return fb
end

---
-- Encode a DNS packet.
--
-- Caution: doesn't encode answer and authority part.
-- @param pkt Table representing DNS packet, initialized by
-- <code>newPacket</code>.
-- @return Encoded DNS packet.
function encode(pkt)
  if type(pkt) ~= "table" then return nil end
  local encFlags = encodeFlags(pkt.flags)
  local additional = encodeAdditional(pkt.additional)
  local aorplen = #pkt.answers
  local data, qorzlen, aorulen

  if ( #pkt.questions > 0 ) then
    data = encodeQuestions( pkt.questions )
    qorzlen = #pkt.questions
    aorulen = 0
  else
    -- The packet has no questions, assume we're dealing with an update
    data = encodeZones( pkt.zones ) .. encodeUpdates( pkt.updates )
    qorzlen = #pkt.zones
    aorulen = #pkt.updates
  end

  local encStr
  if ( pkt.flags.raw ) then
    encStr = string.pack(">I2I2I2I2I2I2", pkt.id, pkt.flags.raw, qorzlen, aorplen, aorulen, #pkt.additional) .. data .. additional
  else
    encStr = string.pack(">I2I2I2I2I2I2", pkt.id, encFlags, qorzlen, aorplen, aorulen, #pkt.additional) .. data .. additional
  end
  return encStr
end


---
-- Decodes a domain in a DNS packet. Handles "compressed" data too.
-- @param data Complete DNS packet.
-- @param pos Starting position in packet.
-- @return Position after decoding.
-- @return Decoded domain, or <code>nil</code> on error.
function decStr(data, pos)
  local function dec(data, pos, limit)
    local partlen
    local parts = {}
    local part

    -- Avoid infinite recursion on malformed compressed messages.
    limit = limit or 10
    if limit < 0 then
      return pos, nil
    end

    partlen, pos = string.unpack(">B", data, pos)
    while (partlen ~= 0) do
      if (partlen < 64) then
        if (#data - pos + 1) < partlen then
          return pos
        end
        part, pos = string.unpack("c" .. partlen, data, pos)
        table.insert(parts, part)
        partlen, pos = string.unpack(">B", data, pos)
      else
        partlen, pos = string.unpack(">I2", data, pos - 1)
        local _, part = dec(data, partlen - 0xC000 + 1, limit - 1)
        if part == nil then
          return pos
        end
        table.insert(parts, part)
        partlen = 0
      end
    end
    return pos, table.concat(parts, ".")
  end

  return dec(data, pos)
end


---
-- Decodes questions in a DNS packet.
-- @param data Complete DNS packet.
-- @param count Value of question counter in header.
-- @param pos Starting position in packet.
-- @return Position after decoding.
-- @return Table of decoded questions.
local function decodeQuestions(data, count, pos)
  local q = {}
  for i = 1, count do
    local currQ = {}
    pos, currQ.dname = decStr(data, pos)
    currQ.dtype, currQ.class, pos = string.unpack(">I2I2", data, pos)
    table.insert(q, currQ)
  end
  return pos, q
end


---
-- Table of functions to decode resource records
local decoder = {}

-- Decodes IP of A record, puts it in <code>entry.ip</code>.
-- @param entry RR in packet.
decoder[types.A] = function(entry)
  entry.ip = ipOps.str_to_ip(entry.data:sub(1,4))
end

-- Decodes IP of AAAA record, puts it in <code>entry.ipv6</code>.
-- @param entry RR in packet.
decoder[types.AAAA] = function(entry)
  entry.ipv6 = ipOps.str_to_ip(entry.data:sub(1,16))
end

-- Decodes SSH fingerprint record, puts it in <code>entry.SSHFP</code> as
-- defined in RFC 4255.
--
-- <code>entry.SSHFP</code> has the fields <code>algorithm</code>,
-- <code>fptype</code>, and <code>fingerprint</code>.
-- @param entry RR in packet.
decoder[types.SSHFP] = function(entry)
  local pos
  entry.SSHFP = {}
  entry.SSHFP.algorithm, entry.SSHFP.fptype, pos = string.unpack(">BB", entry.data)
  entry.SSHFP.fingerprint = stdnse.tohex(entry.data:sub(pos))
end


-- Decodes SOA record, puts it in <code>entry.SOA</code>.
--
-- <code>entry.SOA</code> has the fields <code>mname</code>, <code>rname</code>,
-- <code>serial</code>, <code>refresh</code>, <code>retry</code>,
-- <code>expire</code>, and <code>minimum</code>.
-- @param entry RR in packet.
-- @param data Complete encoded DNS packet.
-- @param pos Position in packet after RR.
decoder[types.SOA] = function(entry, data, pos)

  local np = pos - #entry.data

  entry.SOA = {}

  np, entry.SOA.mname = decStr(data, np)
  np, entry.SOA.rname = decStr(data, np)
  entry.SOA.serial,
  entry.SOA.refresh,
  entry.SOA.retry,
  entry.SOA.expire,
  entry.SOA.minimum,
  np = string.unpack(">I4I4I4I4I4", data, np)
end

-- An iterator that returns the positions of nonzero bits in the given binary
-- string.
local function bit_iter(bits)
  return coroutine.wrap(function()
    for i = 1, #bits do
      local n = string.byte(bits, i)
      local j = 0
      local mask = 0x80

      while mask > 0 do
        if (n & mask) ~= 0 then
          coroutine.yield((i - 1) * 8 + j)
        end
        j = j + 1
        mask = (mask >> 1)
      end
    end
  end)
end

-- Decodes NSEC records, puts result in <code>entry.NSEC</code>. See RFC 4034,
-- section 4.
--
-- <code>entry.NSEC</code> has the fields <code>dname</code>,
-- <code>next_dname</code>, and <code>types</code>.
-- @param entry RR in packet.
-- @param data Complete encoded DNS packet.
-- @param pos Position in packet after RR.
decoder[types.NSEC] = function (entry, data, pos)
  local np = pos - #entry.data
  entry.NSEC = {}
  entry.NSEC.dname = entry.dname
  np, entry.NSEC.next_dname = decStr(data, np)
  while np < pos do
    local block_num, type_bitmap
    block_num, type_bitmap, np = string.unpack(">Bs1", data, np)
    entry.NSEC.types = {}
    for i in bit_iter(type_bitmap) do
      entry.NSEC.types[(block_num - 1) * 256 + i] = true
    end
  end
end
-- Decodes NSEC3 records, puts result in <code>entry.NSEC3</code>. See RFC 5155.
--
-- <code>entry.NSEC3</code> has the fields <code>dname</code>,
-- <code>hash.alg</code>, and <code>hash.base32</code>.
-- <code>hash.bin</code>, and <code>hash.hex</code>.
-- <code>salt.bin</code>, and <code>salt.hex</code>.
-- <code>iterations</code>, and <code>types</code>.
-- @param entry RR in packet.
-- @param data Complete encoded DNS packet.
-- @param pos Position in packet after RR.
decoder[types.NSEC3] = function (entry, data, pos)
  local np = pos - #entry.data
  local _
  local flags

  entry.NSEC3 = {}
  entry.NSEC3.dname = entry.dname
  entry.NSEC3.salt, entry.NSEC3.hash = {}, {}

  entry.NSEC3.hash.alg, entry.NSEC3.flags, entry.NSEC3.iterations, np = string.unpack(">BBI2", data, np)
  -- do we even need to decode these do we care about opt out?
  -- entry.NSEC3.flags = decodeFlagsNSEC3(flags)

  entry.NSEC3.salt.bin, np = string.unpack(">s1",  data, np)
  entry.NSEC3.salt.hex = stdnse.tohex(entry.NSEC3.salt.bin)

  entry.NSEC3.hash.bin, np = string.unpack(">s1" , data, np)
  entry.NSEC3.hash.hex = stdnse.tohex(entry.NSEC3.hash.bin)
  entry.NSEC3.hash.base32 = base32.enc(entry.NSEC3.hash.bin, true)

  entry.NSEC3.WinBlockNo, entry.NSEC3.bin, np = string.unpack(">Bs1", data, np)
  entry.NSEC3.types = {}
  for i in bit_iter(entry.NSEC3.bin) do
    entry.NSEC3.types[(entry.NSEC3.WinBlockNo - 1) * 256 + i] = true
  end
end

-- Decodes records that consist only of one domain, for example CNAME, NS, PTR.
-- Puts result in <code>entry.domain</code>.
-- @param entry RR in packet.
-- @param data Complete encoded DNS packet.
-- @param pos Position in packet after RR.
local function decDomain(entry, data, pos)
  local np = pos - #entry.data
  local _
  _, entry.domain = decStr(data, np)
end

-- Decodes CNAME records.
-- Puts result in <code>entry.domain</code>.
-- @name decoder[types.CNAME]
-- @class function
-- @param entry RR in packet.
-- @param data Complete encoded DNS packet.
-- @param pos Position in packet after RR.
decoder[types.CNAME] = decDomain

-- Decodes NS records.
-- Puts result in <code>entry.domain</code>.
-- @name decoder[types.NS]
-- @class function
-- @param entry RR in packet.
-- @param data Complete encoded DNS packet.
-- @param pos Position in packet after RR.
decoder[types.NS] = decDomain

-- Decodes PTR records.
-- Puts result in <code>entry.domain</code>.
-- @name decoder[types.PTR]
-- @class function
-- @param entry RR in packet.
-- @param data Complete encoded DNS packet.
-- @param pos Position in packet after RR.
decoder[types.PTR] = decDomain

-- Decodes TXT records.
-- Puts result in <code>entry.domain</code>.
-- @name decoder[types.TXT]
-- @class function
-- @param entry RR in packet.
-- @param data Complete encoded DNS packet.
-- @param pos Position in packet after RR.
decoder[types.TXT] =
function (entry, data, pos)

  local len = entry.data:len()
  local np = pos - #entry.data
  local txt_len
  local txt

  if len > 0 then
    entry.TXT = {}
    entry.TXT.text = {}
  end

  while np < len do
    txt, np = string.unpack("s1", data, np)
    table.insert( entry.TXT.text, txt )
  end

end

---
-- Decodes OPT record, puts it in <code>entry.OPT</code>.
--
-- <code>entry.OPT</code> has the fields <code>mname</code>, <code>rname</code>,
-- <code>serial</code>, <code>refresh</code>, <code>retry</code>,
-- <code>expire</code>, and <code>minimum</code>.
-- @param entry RR in packet.
-- @param data Complete encoded DNS packet.
-- @param pos Position in packet after RR.
decoder[types.OPT] =
function(entry, data, pos)
  local np = pos - #entry.data - 6
  local opt = { bufsize = entry.class }
  opt.rcode, opt.version, opt.zflags, opt.data, np = string.unpack(">BBI2s2", data, np)
  entry.OPT = opt
end


-- Decodes MX record, puts it in <code>entry.MX</code>.
--
-- <code>entry.MX</code> has the fields <code>pref</code> and
-- <code>server</code>.
-- @param entry RR in packet.
-- @param data Complete encoded DNS packet.
-- @param pos Position in packet after RR.
decoder[types.MX] =
function(entry, data, pos)
  local np = pos - #entry.data + 2
  local _
  entry.MX = {}
  entry.MX.pref = string.unpack(">I2", entry.data)
  _, entry.MX.server = decStr(data, np)
end

-- Decodes SRV record, puts it in <code>entry.SRV</code>.
--
-- <code>entry.SRV</code> has the fields <code>prio</code>,
-- <code>weight</code>, <code>port</code> and
-- <code>target</code>.
-- @param entry RR in packet.
-- @param data Complete encoded DNS packet.
-- @param pos Position in packet after RR.
decoder[types.SRV] =
function(entry, data, pos)
  local np = pos - #entry.data
  local _
  entry.SRV = {}
  entry.SRV.prio, entry.SRV.weight, entry.SRV.port, np = string.unpack(">I2I2I2", data, np)
  np, entry.SRV.target = decStr(data, np)
end

-- Decodes returned resource records (answer, authority, or additional part).
-- @param data Complete encoded DNS packet.
-- @param count Value of according counter in header.
-- @param pos Starting position in packet.
-- @return Table of RRs.
local function decodeRR(data, count, pos)
  local ans = {}
  for i = 1, count do
    local currRR = {}
    pos, currRR.dname = decStr(data, pos)
    currRR.dtype, currRR.class, currRR.ttl, pos = string.unpack(">I2I2I4", data, pos)

    currRR.data, pos = string.unpack(">s2", data, pos)

    -- try to be smart: decode per type
    if decoder[currRR.dtype] then
      decoder[currRR.dtype](currRR, data, pos)
    end

    table.insert(ans, currRR)
  end
  return pos, ans
end

---
-- Decodes DNS flags.
-- @param flgStr Flags as a binary digit string.
-- @return Table representing flags.
local function decodeFlags(flags)
  local tflags = {}
  if (flags & 0x8000) ~= 0 then tflags.QR  = true end
  if (flags & 0x4000) ~= 0 then tflags.OC1 = true end
  if (flags & 0x2000) ~= 0 then tflags.OC2 = true end
  if (flags & 0x1000) ~= 0 then tflags.OC3 = true end
  if (flags & 0x0800) ~= 0 then tflags.OC4 = true end
  if (flags & 0x0400) ~= 0 then tflags.AA  = true end
  if (flags & 0x0200) ~= 0 then tflags.TC  = true end
  if (flags & 0x0100) ~= 0 then tflags.RD  = true end
  if (flags & 0x0080) ~= 0 then tflags.RA  = true end
  if (flags & 0x0008) ~= 0 then tflags.RC1 = true end
  if (flags & 0x0004) ~= 0 then tflags.RC2 = true end
  if (flags & 0x0002) ~= 0 then tflags.RC3 = true end
  if (flags & 0x0001) ~= 0 then tflags.RC4 = true end
  return tflags
end

---
-- Decodes a DNS packet.
-- @param data Encoded DNS packet.
-- @return Table representing DNS packet.
function decode(data)
  local pos
  local pkt = {}
  local encFlags
  local cnt = {}
  pkt.id, encFlags, cnt.q, cnt.a, cnt.auth, cnt.add, pos = string.unpack(">I2I2I2I2I2I2", data)
  -- for now, don't decode the flags
  pkt.flags = decodeFlags(encFlags)

  --
  -- check whether this is an update response or not
  -- a quick fix to allow decoding of non updates and not break for updates
  -- the flags are enough for the current code to determine whether an update was successful or not
  --
  local flags = encodeFlags(pkt.flags)
  -- QR, OC2
  if (flags & 0xF000) == 0xA000 then
    return pkt
  else
    pos, pkt.questions = decodeQuestions(data, cnt.q, pos)
    pos, pkt.answers = decodeRR(data, cnt.a, pos)
    pos, pkt.auth = decodeRR(data, cnt.auth, pos)
    pos, pkt.add = decodeRR(data, cnt.add, pos)
  end
  return pkt
end


---
-- Creates a new table representing a DNS packet.
-- @return Table representing a DNS packet.
function newPacket()
  local pkt = {}
  pkt.id = 1
  pkt.flags = {}
  pkt.flags.RD = true
  pkt.questions = {}
  pkt.zones = {}
  pkt.updates = {}
  pkt.answers = {}
  pkt.auth = {}
  pkt.additional = {}
  return pkt
end


---
-- Adds a question to a DNS packet table.
-- @param pkt Table representing DNS packet.
-- @param dname Domain name to be asked.
-- @param dtype RR to be asked.
function addQuestion(pkt, dname, dtype, class)
  if type(pkt) ~= "table" then return nil end
  if type(pkt.questions) ~= "table" then return nil end
  local class = class or CLASS.IN
  local q = {}
  q.dname = dname
  q.dtype = dtype
  q.class = class
  table.insert(pkt.questions, q)
  return pkt
end


get_default_timeout = function()
  local timeout = {[0] = 10000, 7000, 5000, 4000, 4000, 4000}
  return timeout[nmap.timing_level()] or 4000
end

---
-- Adds a zone to a DNS packet table
-- @param pkt Table representing DNS packet.
-- @param dname Domain name to be asked.
function addZone(pkt, dname)
  if ( type(pkt) ~= "table" ) or (type(pkt.updates) ~= "table") then return nil end
  table.insert(pkt.zones, { dname=dname, dtype=types.SOA, class=CLASS.IN })
  return pkt
end

---
-- Encodes the Z bitfield of an OPT record.
-- @param flags Flag table, each entry representing a flag (only DO flag implmented).
-- @return Binary digit string representing flags.
local function encodeOPT_Z(flags)
  if type(flags) == "number" then return flags end
  assert(type(flags) == "table")
  local bits = 0
  if flags.DO then bits = bits|0x8000 end
  return bits
end

---
-- Adds an client-subnet payload to the OPT packet
--
-- implementing https://tools.ietf.org/html/rfc7871
-- @param pkt Table representing DNS packet.
-- @param Z Table of Z flags. Only DO is supported.
-- @param client_subnet table containing the following fields
--        <code>family</code>  - IPv4: "inet" or 1 (default), IPv6: "inet6" or 2
--        <code>mask</code>    - byte containing the length of the subnet mask
--        <code>address</code> - string containing the IP address
function addClientSubnet(pkt,Z,subnet)
  local family = subnet.family or 1
  if type(family) == "string" then
    family = ({inet=1,inet6=2})[family]
  end
  assert(family == 1 or family == 2, "Unsupported subnet family")
  local code = 8 -- https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-11
  local mask = subnet.mask
  local scope_mask = 0 -- In requests, it MUST be set to 0
  -- Per RFC 7871, section 6:
  -- Address must have all insignificant bits zeroed out and insignificant bytes
  -- must be trimmed off. (/24 IPv4 address is submitted as 3 octets, not 4.)
  local addr = ipOps.get_first_ip(subnet.address, mask)
  addr = ipOps.ip_to_str(addr):sub(1, (mask + 7) // 8)
  local data = string.pack(">I2BB", family, mask, scope_mask) .. addr
  local opt = string.pack(">I2s2", code, data)
  addOPT(pkt,Z,opt)
end

---
-- Adds an NSID payload to the OPT packet
-- @param pkt Table representing DNS packet.
-- @param Z Table of Z flags. Only DO is supported.
function addNSID (pkt,Z)
  local opt = string.pack(">I2I2", 3, 0) -- nsid data
  addOPT(pkt,Z,opt)
end

---
-- Adds an OPT RR to a DNS packet's additional section.
--
-- Only the table of Z flags is supported (i.e., not RDATA). See RFC 2671
-- section 4.3.
-- @param pkt Table representing DNS packet.
-- @param Z Table of Z flags. Only DO is supported.
function addOPT(pkt, Z, opt)
  local rdata = opt or ""
  if type(pkt) ~= "table" then return nil end
  if type(pkt.additional) ~= "table" then return nil end
  local Z_int = encodeOPT_Z(Z)
  local opt = {
    type = types.OPT,
    class = 4096,  -- Actually the sender UDP payload size.
    ttl = 0 * (0x01000000) + 0 * (0x00010000) + Z_int,
    rdata = rdata,
  }
  table.insert(pkt.additional, opt)
  return pkt
end

---
-- Adds a update to a DNS packet table
-- @param pkt Table representing DNS packet.
-- @param dname Domain name to be asked.
-- @param dtype to be updated
-- @param ttl the time-to-live of the record
-- @param data type specific data
function addUpdate(pkt, dname, dtype, ttl, data, class)
  if ( type(pkt) ~= "table" ) or (type(pkt.updates) ~= "table") then return nil end
  table.insert(pkt.updates, { dname=dname, dtype=dtype, class=class, ttl=ttl, data=(data or "") } )
  return pkt
end


--- Adds a record to the Zone
-- @param dname containing the hostname to add
-- @param options A table containing any of the following fields:
-- * <code>dtype</code>: Desired DNS record type (default: <code>"A"</code>).
-- * <code>host</code>: DNS server to be queried (default: DNS servers known to Nmap).
-- * <code>timeout</code>: The time to wait for a response
-- * <code>sendCount</code>: The number of send attempts to perform
-- * <code>zone</code>: If not supplied deduced from hostname
-- * <code>data</code>: Table or string containing update data (depending on record type):
--  A     - String containing the IP address
--  CNAME - String containing the FQDN
--  MX   - Table containing <code>pref</code>, <code>mx</code>
--  SRV - Table containing <code>prio</code>, <code>weight</code>, <code>port</code>, <code>target</code>
--
-- @return status true on success false on failure
-- @return msg containing the error message
--
-- Examples
--
-- Adding different types of records to a server
--  * update( "www.cqure.net", { host=host, port=port, dtype="A", data="10.10.10.10" } )
--  * update( "alias.cqure.net", { host=host, port=port, dtype="CNAME", data="www.cqure.net" } )
--  * update( "cqure.net", { host=host, port=port, dtype="MX", data={ pref=10, mx="mail.cqure.net"} })
--  * update( "_ldap._tcp.cqure.net", { host=host, port=port, dtype="SRV", data={ prio=0, weight=100, port=389, target="ldap.cqure.net" } } )
--
-- Removing the above records by setting an empty data and a ttl of zero
--  * update( "www.cqure.net", { host=host, port=port, dtype="A", data="", ttl=0 } )
--  * update( "alias.cqure.net", { host=host, port=port, dtype="CNAME", data="", ttl=0 } )
--  * update( "cqure.net", { host=host, port=port, dtype="MX", data="", ttl=0 } )
--  * update( "_ldap._tcp.cqure.net", { host=host, port=port, dtype="SRV", data="", ttl=0 } )
--
function update(dname, options)
  local options = options or {}
  local pkt = newPacket()
  local flags = pkt.flags
  local host, port = options.host, options.port
  local timeout = ( type(options.timeout) == "number" ) and options.timeout or get_default_timeout()
  local sendcount = options.sendCount or 2
  local dtype = ( type(options.dtype) == "string" ) and types[options.dtype] or types.A
  local updata = options.data
  local ttl = options.ttl or 86400
  local zone = options.zone or dname:match("^.-%.(.+)$")
  local class = CLASS.IN

  assert(host, "dns.update needs a valid host in options")
  assert(port, "dns.update needs a valid port in options")

  if ( options.zone ) then dname = dname .. "." .. options.zone end

  if ( not(zone) and not( dname:match("^.-%..+") ) ) then
    return false, "hostname needs to be supplied as FQDN"
  end

  flags.RD = false
  flags.OC1, flags.OC2, flags.OC3, flags.OC4 = false, true, false, true

  -- If ttl is zero and updata is nil or a string of zero length, assume delete record
  if ttl == 0 and (not updata or (type(updata) == "string" and #updata == 0)) then
    class = CLASS.ANY
    updata = ""
    if ( types.MX == dtype and not(options.zone) ) then zone=dname end
    if ( types.SRV == dtype and not(options.zone) ) then
      zone=dname:match("^_.-%._.-%.(.+)$")
    end
    -- if not, let's try to update the zone
  else
    if ( dtype == types.A or dtype == types.AAAA ) then
      updata = updata and ipOps.ip_to_str(updata) or ""
    elseif( dtype == types.CNAME ) then
      updata = encodeFQDN(updata)
    elseif( dtype == types.MX ) then
      assert( not( type(updata) ~= "table" ), "dns.update expected options.data to be a table")
      if ( not(options.zone) ) then zone = dname end
      local data = string.pack(">I2", updata.pref)
      data = data .. encodeFQDN(updata.mx)
      updata = data
    elseif ( dtype == types.SRV ) then
      assert( not( type(updata) ~= "table" ), "dns.update expected options.data to be a table")
      local data = string.pack(">I2I2I2", updata.prio, updata.weight, updata.port )
      data = data .. encodeFQDN(updata.target)
      updata = data
      zone = options.zone or dname:match("^_.-%._.-%.(.+)$")
    else
      return false, "Unsupported record type"
    end
  end

  pkt = addZone(pkt, zone)
  pkt = addUpdate(pkt, dname, dtype, ttl, updata, class)

  local data = encode(pkt)
  local status, response = sendPackets(data, host, port, timeout, sendcount, false)

  if ( status ) then
    local decoded = decode(response[1].data)
    local flags = encodeFlags(decoded.flags)
    if (flags & 0xF) == 0 then
      return true
    end
  end
  return false
end

if not unittest.testing() then
  return _ENV
end

-- Self test
test_suite = unittest.TestSuite:new()

test_suite:add_test(unittest.equal(encodeFQDN("test.me.com"), "\x04test\x02me\x03com\0"), "encodeFQDN")
return _ENV;

Youez - 2016 - github.com/yon3zu
LinuXploit