├── .gitignore ├── Changes ├── LICENSE ├── Makefile ├── README ├── lua ├── dns.lua ├── mx.lua └── test.lua ├── notes ├── org.conman.dns-2.1.3-1.rockspec └── src ├── codec.c ├── dns.h ├── dotest.c ├── luadns.c ├── mappings.c ├── mappings.h ├── netsimple.c ├── netsimple.h ├── output.c └── output.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a 3 | *.so 4 | *~ 5 | -------------------------------------------------------------------------------- /Changes: -------------------------------------------------------------------------------- 1 | 2 | v2.0.0 3 | 4 | * Encoding of multiple DNS records now supported 5 | * Lua now returns integer error instead of string (API change for Lua) 6 | 7 | v1.0.19 8 | 9 | * Fix compilation errors when using Lua 5.1 10 | 11 | v1.0.18 12 | 13 | * Update code to compile with Lua 5.4 14 | 15 | v1.0.17 16 | 17 | * Bug fix---Increase packet buffer size in Lua code. 18 | 19 | v1.0.16 20 | 21 | * Bug fix---Forgot to set class field when using OPT RR 22 | 23 | v1.0.15 24 | 25 | * Bug fix---invalid write to memory 26 | 27 | v1.0.14 28 | 29 | * Bug fix---unused bit goes into the z field 30 | 31 | v1.0.13 32 | 33 | * Bug fix---compiling/linking issues 34 | 35 | v1.0.12 36 | 37 | * Update code to compile with Lua 5.2 and 5.3 38 | 39 | v1.0.11 40 | 41 | * Bug fix---fix typo 42 | 43 | v1.0.10 44 | 45 | * Bug fix---remove undefined behavior from previous bug fix 46 | 47 | v1.0.9 48 | 49 | * Bug fix---concatenated TXT records need space between strings 50 | 51 | v1.0.8 52 | 53 | * Bug fix---timed out condition didn't return timed out error 54 | 55 | v1.0.7 56 | 57 | * Rockspec update 58 | 59 | v1.0.6 60 | 61 | * Rockspec update 62 | 63 | v1.0.5 64 | 65 | * Support for Lua rocks 66 | 67 | v1.0.4 68 | 69 | * Fixed __attribute__() 70 | 71 | v1.0.3 72 | 73 | * Bug fix-return unknown values 74 | 75 | v1.0.2 76 | 77 | * C++ compilation errors fixed 78 | 79 | v1.0.1 80 | 81 | * Added some asserts 82 | 83 | v1.0.0 84 | 85 | * Initial version. 86 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | ####################################################################### 3 | # 4 | # Copyright 2010 by Sean Conner. All Rights Reserved. 5 | # 6 | # This library is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU Lesser General Public License as published by 8 | # the Free Software Foundation; either version 3 of the License, or (at your 9 | # option) any later version. 10 | # 11 | # This library is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 14 | # License for more details. 15 | # 16 | # You should have received a copy of the GNU Lesser General Public License 17 | # along with this library; if not, see . 18 | # 19 | ###################################################################### 20 | 21 | UNAME := $(shell uname) 22 | VERSION := $(shell git describe --tag) 23 | 24 | ifeq ($(VERSION),) 25 | VERSION=v2.1.3 26 | endif 27 | 28 | # =================================================== 29 | 30 | CC = gcc -std=c99 -Wall -Wextra -pedantic -Wwrite-strings 31 | CFLAGS = -g 32 | LDFLAGS = -g 33 | LDLIBS = -lm 34 | 35 | ifeq ($(UNAME),Linux) 36 | CSHARE = -fPIC 37 | LDSHARE = -g -shared 38 | endif 39 | 40 | ifeq ($(UNAME),Darwin) 41 | CSHARE = -fPIC 42 | LDSHARE = -g -bundle -undefined dynamic_lookup -all_load 43 | endif 44 | 45 | #================================================= 46 | 47 | INSTALL = /usr/bin/install 48 | INSTALL_PROGRAM = $(INSTALL) 49 | INSTALL_DATA = $(INSTALL) -m 644 50 | 51 | prefix = /usr/local 52 | libdir = $(prefix)/lib 53 | 54 | LUA ?= lua 55 | LUA_VERSION := $(shell $(LUA) -e "print(_VERSION:match '^Lua (.*)')") 56 | LIBDIR ?= $(libdir)/lua/$(LUA_VERSION) 57 | 58 | ifneq ($(LUA_INCDIR),) 59 | src/dns.so : override CFLAGS += -I$(LUA_INCDIR) 60 | endif 61 | 62 | #================================================= 63 | 64 | %.a : 65 | $(AR) $(ARFLAGS) $@ $? 66 | 67 | %.oo : %.c 68 | $(CC) $(CFLAGS) -DVERSION='"$(VERSION)"' $(CSHARE) -c -o $@ $< 69 | 70 | %.so : 71 | $(CC) $(LDSHARE) -o $@ $^ 72 | 73 | #================================================= 74 | 75 | .PHONY: all install-lua uninstall-lua clean dist depend 76 | all : src/dotest src/libspcdns.a src/dns.so 77 | 78 | src/dotest : src/dotest.o src/libspcdns.a 79 | src/libspcdns.a : src/codec.o src/mappings.o src/netsimple.o src/output.o 80 | src/dns.so : src/luadns.oo src/codec.oo src/mappings.oo src/netsimple.oo 81 | 82 | install-lua : src/dns.so 83 | $(INSTALL) -d $(DESTDIR)$(LIBDIR)/org/conman 84 | $(INSTALL_PROGRAM) src/dns.so $(DESTDIR)$(LIBDIR)/org/conman 85 | 86 | uninstall-lua : 87 | $(RM) $(DESTDIR)$(LIBDIR)/org/conman/dns.so 88 | 89 | clean: 90 | $(RM) $(shell find . -name '*.o') 91 | $(RM) $(shell find . -name '*.so') 92 | $(RM) $(shell find . -name '*.oo') 93 | $(RM) $(shell find . -name '*.a') 94 | $(RM) $(shell find . -name '*~') 95 | $(RM) Makefile.bak src/dotest 96 | 97 | dist: 98 | git archive -o /tmp/spcdns-$(VERSION).tar.gz --prefix spcdns/ $(VERSION) 99 | 100 | depend: 101 | makedepend -Y -- $(CFLAGS) -- src/*.c 2>/dev/null 102 | 103 | # DO NOT DELETE 104 | 105 | src/codec.o: src/dns.h 106 | src/dotest.o: src/dns.h src/mappings.h src/netsimple.h src/output.h 107 | src/luadns.o: src/dns.h src/mappings.h src/netsimple.h 108 | src/mappings.o: src/dns.h src/mappings.h 109 | src/netsimple.o: src/dns.h src/netsimple.h 110 | src/output.o: src/dns.h src/mappings.h src/output.h 111 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | SPCDNS: The sane DNS encoding/decoding library 3 | 4 | SPCDNS implements a simple yet sane API to encode DNS queries and to decode 5 | DNS replies. The library (v2.0.0) currently supports the encoding and 6 | decoding of 30 DNS resource records, which is more than just about all other 7 | DNS resolving libraries I've seen (c-ares, udns, adns, libdns and djbdns 8 | [1]). 9 | 10 | SPCDNS is *NOT* a general purpose DNS resolving library (although code is 11 | provided to make DNS queries, it is simple and fairly stupid). This code 12 | exists to provide a simple method of encoding and decoding the DNS protocol 13 | and thus the network side of things is a bit lacking I'll admit. But that 14 | is beyond what I wanted for this project anyway. 15 | 16 | In the "src/" directory you'll find the following: 17 | 18 | dns.h 19 | 20 | Defines the various DNS RR types, a structure for an 21 | in-memory representation of each RR type (which is what 22 | you'll get back when you call the decoding routine), and the 23 | definitions for two functions, dns_encode() and dns_decode() 24 | which pretty much do what they say. 25 | 26 | codec.c 27 | 28 | The actual implementations of dns_encode() and dns_decode(). 29 | This is the only file that's needed to encode and decode the 30 | raw DNS protocol. The routines are thread safe, do *not* 31 | allocate memory (see below for more details) and do not use 32 | signals. It also does not use code from any other file in 33 | this package. 34 | 35 | mappings.h 36 | mappings.c 37 | 38 | These files provide definitions and implementation of a few 39 | helpful routines that return string representations of the 40 | DNS RR types, classes, opcodes and errors. Again, thread 41 | safe and no memory allocations made. 42 | 43 | netsimple.h 44 | netsimple.c 45 | 46 | These files provide definitions and implementations for 47 | making simple DNS queries to a given server. This code is 48 | *simple* and *dumb*, it may be good for light usage but was 49 | written to get actual DNS packets from a DNS server for 50 | testing. This uses UDP and is thus limited to a query of 51 | 512 bytes or less. 52 | 53 | output.h 54 | output.c 55 | 56 | These files provide definitions and implementations for 57 | utility functions to print query results using C stdio. 58 | It was factored out of the unit tests for debugging client 59 | applications making using of libspcdns.a and libspcdns.so. 60 | They are found in the libspcdnsmisc.a and libspcdnsmisc.so 61 | libraries. 62 | 63 | luadns.c 64 | 65 | Lua [2] bindings for this library. It exports the routines 66 | found in codec.c, mappings.c and netsimple.c. 67 | 68 | dotest.c 69 | 70 | An example program showing how to use the API to construct 71 | and send a query, and to decode the response. 72 | 73 | You'll probably want to check the Makefile to make sure the right compiler 74 | and locations are set. Or not. You don't *HAVE* to use the included 75 | Makefile. It's really just a set of suggestions anyway. 76 | 77 | A NOTE ABOUT MEMORY ALLOCATIONS 78 | 79 | The dns_encode() and dns_decode() functions do no memory allocation; they 80 | use what you give them. In the case of dns_decode(), the block of memory 81 | passed in must be big enough to handle not only the dns_query_t structure, 82 | but multiple dns_answer_t structures and text strings representing domain 83 | names and the occasional string or two (say, for TXT or NAPTR records). In 84 | testing, I've found that 4K for decoding appears to be enough memory to 85 | handle DNS requests made via UDP (although the test.c program uses an 8K 86 | buffer). 87 | 88 | This block of memory should be properly aligned and to help make that easier 89 | I've defined two data types that should allow proper alignment, along with 90 | some useful constants to declare buffers of proper alignment and size. 91 | 92 | dns_packet_t reply [DNS_BUFFER_UDP]; 93 | dns_decoded_t decoded[DNS_DECODEBUF_4K]; 94 | dns_query_t *result; 95 | dns_rcode rc; 96 | size_t replysize; 97 | size_t decodesize; 98 | 99 | /* assume reply contains a DNS packet, and replysize is set */ 100 | 101 | decodesize = sizeof(decoded); 102 | rc = dns_decode(decoded,&decodesize,reply,replysize); 103 | 104 | if (rc != RCODE_OKAY) 105 | { 106 | /* handle error */ 107 | } 108 | 109 | result = (dns_query_t *)decoded; 110 | 111 | /* go with processing the result */ 112 | 113 | Do *NOT* assume that DNS_DECODEBUF_4K is equal to 4096---it's not. It 114 | *DOES*, however, result in at least a 4K block of memory made up of 115 | DNS_DECODEBUF_4K worth of dns_decoded_t types. By the same token, do *NOT* 116 | assume that DNS_BUFFER_UDP is 512, but it too, does result in a buffer of at 117 | least 512 bytes made up of DNS_BUFFER_UDP dns_packet_t types. 118 | 119 | And while passing in a char * declared buffer to dns_decode() may appear to 120 | work, it only works on *YOUR* system; it may not work on other systems. 121 | 122 | A NOTE ABOUT DOMAIN NAMES 123 | 124 | The dns_encode() function assumes the domain passed is a fully qualified 125 | domain name. If you see an RCODE_NAME_ERROR when calling this function, you 126 | are probably not passing in a FQDN (if you are and are still getting that 127 | error, it's most likely a domain name segment exceeding the 63 character DNS 128 | limit). 129 | 130 | SOME NOTES ABOUT THE LUA BINDINGS 131 | 132 | The Lua bindings (for Lua 5.1-5.4) are loaded into a Lua script with the 133 | following: 134 | 135 | local dns = require "org.conman.dns" 136 | 137 | Doing a "make install-lua" will install this file under: 138 | 139 | /usr/local/lib/lua//org/conman/ 140 | 141 | (assuming you didn't change the LUA setting in the Makefile) 142 | 143 | and thus place it under the appropriate namespace so Lua can find it. 144 | 145 | The file "lua/test.lua" shows the best use of the Lua bindings (and is close 146 | enough to what "src/test.c" does). Better network handling could be done 147 | using LuaSocket, but for that, you are on your own. 148 | 149 | UNIT TESTING 150 | 151 | The dotest program allows unit-testing SPCDNS when making changes or 152 | integrating it with client applications. 153 | 154 | Note: the unit test program, dotest, requires a fully-qualified canonical DNS 155 | name. This means "www.example.com." NOT "www.example.com". If this is not 156 | present, the dns_encode_domain function returns RCODE_NAME_ERROR and the test 157 | will fail with a mysterious error message. 158 | 159 | Sample Output: 160 | 161 | This is an example of a working run, querying for Google's web server, using a 162 | Google Public DNS Server [4]. 163 | 164 | $ ./dotest -d -s 8.8.8.8 www.google.com. 165 | OUTGOING: 166 | 167 | ... MEMORY DUMP... 168 | 169 | INCOMING: 170 | 171 | ... MEMORY DUMP... 172 | 173 | Bytes used: 680 174 | 175 | ; Questions = 1 176 | ; Answers = 5 177 | ; Name Servers = 0 178 | ; Additional Records = 0 179 | ; Authoritative Result = false 180 | ; Truncated Result = false 181 | ; Recursion Desired = true 182 | ; Recursion Available = true 183 | ; Result = No error 184 | 185 | ;;; QUESTIONS 186 | 187 | ;www.google.com. IN A 188 | 189 | ;;; ANSWERS 190 | 191 | www.google.com. 185 IN A 74.125.239.49 192 | www.google.com. 185 IN A 74.125.239.52 193 | www.google.com. 185 IN A 74.125.239.50 194 | www.google.com. 185 IN A 74.125.239.51 195 | www.google.com. 185 IN A 74.125.239.48 196 | 197 | ;;; NAMESERVERS 198 | 199 | 200 | ;;; ADDITIONAL 201 | 202 | A FINAL NOTE 203 | 204 | If you have any problems, questions or enhancements, please send them my 205 | way, to sean@conman.org. 206 | 207 | Thank you. 208 | 209 | Other contributors include, but are not limited to: 210 | 211 | Matthew Hall 212 | 213 | [1] http://c-ares.haxx.se/ 214 | http://www.corpit.ru/mjt/udns.html 215 | http://www.chiark.greenend.org.uk/~ian/adns/ 216 | http://www.25thandclement.com/~william/projects/dns.c.html 217 | http://cr.yp.to/djbdns.html 218 | 219 | [2] http://www.lua.org/ 220 | 221 | [3] http://w3.impa.br/~diego/software/luasocket/ 222 | 223 | [4] https://developers.google.com/speed/public-dns/ 224 | -------------------------------------------------------------------------------- /lua/dns.lua: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env lua 2 | -- ************************************************************************* 3 | -- 4 | -- Copyright 2010 by Sean Conner. All Rights Reserved. 5 | -- 6 | -- This library is free software; you can redistribute it and/or modify it 7 | -- under the terms of the GNU Lesser General Public License as published by 8 | -- the Free Software Foundation; either version 3 of the License, or (at your 9 | -- option) any later version. 10 | -- 11 | -- This library is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 14 | -- License for more details. 15 | -- 16 | -- You should have received a copy of the GNU Lesser General Public License 17 | -- along with this library; if not, see . 18 | -- 19 | -- ************************************************************************** 20 | 21 | local dns = require "org.conman.dns" 22 | 23 | local e = dns.encode { 24 | id = 1234, 25 | query = true, 26 | rd = true, 27 | opcode = 'query', 28 | question = { 29 | name = 'yahoo.com.', 30 | type = 'mx', 31 | class = 'in' 32 | } 33 | } 34 | 35 | local r,err = dns.query('127.0.0.1',e) 36 | 37 | if r == nil then 38 | print("error:",err) 39 | os.exit(1) 40 | end 41 | 42 | local d = dns.decode(r) 43 | 44 | for i = 1 , #d.answers do 45 | print(string.format("%s %d %s %s %d %s", 46 | d.answers[i].name, 47 | d.answers[i].ttl, 48 | d.answers[i].class, 49 | d.answers[i].type, 50 | d.answers[i].preference, 51 | d.answers[i].exchange 52 | )) 53 | end 54 | 55 | -------------------------------------------------------------------------------- /lua/mx.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env lua 2 | -- ************************************************************************* 3 | -- 4 | -- Copyright 2010 by Sean Conner. All Rights Reserved. 5 | -- 6 | -- This library is free software; you can redistribute it and/or modify it 7 | -- under the terms of the GNU Lesser General Public License as published by 8 | -- the Free Software Foundation; either version 3 of the License, or (at your 9 | -- option) any later version. 10 | -- 11 | -- This library is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 14 | -- License for more details. 15 | -- 16 | -- You should have received a copy of the GNU Lesser General Public License 17 | -- along with this library; if not, see . 18 | -- 19 | -- ************************************************************************** 20 | -- luacheck: ignore 611 21 | 22 | local SERVER = "127.0.0.1" 23 | local dns = require "org.conman.dns" 24 | 25 | -- ************************************************************** 26 | 27 | local function query(host,type) 28 | local e = dns.encode { 29 | id = math.random(65535), 30 | query = true, 31 | rd = true, 32 | opcode = 'query', 33 | question = { 34 | name = host, 35 | type = type, 36 | class = 'in' 37 | } 38 | } 39 | 40 | local r,err = dns.query(SERVER,e) 41 | 42 | if r == nil then 43 | print("error:",err) 44 | return nil 45 | end 46 | 47 | return dns.decode(r) 48 | end 49 | 50 | -- **************************************************************** 51 | 52 | local function query_a(host) 53 | local a,err = query(host,'a') 54 | 55 | if a == nil then 56 | print("error:",err) 57 | return nil 58 | end 59 | 60 | return a.answers[1] 61 | end 62 | 63 | -- **************************************************************** 64 | 65 | local function query_mx(host) 66 | local mx,err = query(host,'mx') 67 | 68 | if mx == nil then 69 | print("error:",err) 70 | return nil 71 | end 72 | 73 | table.sort(mx.answers,function(a,b) return a.preference < b.preference end) 74 | 75 | for i = 1 , #mx.answers do 76 | mx.answers[i].ADDRESS = mx.additional[mx.answers[i].exchange] 77 | if mx.answers[i].ADDRESS == nil then 78 | mx.answers[i].ADDRESS = query_a(mx.answers[i].exchange) 79 | end 80 | end 81 | 82 | return mx.answers 83 | end 84 | 85 | -- ************************************************************** 86 | 87 | if #arg == 0 then 88 | io.stderr:write(string.format("usage: %s domain\n",arg[0])) 89 | os.exit(1) 90 | end 91 | 92 | local results = query_mx(arg[1]) 93 | 94 | for i = 1 , #results do 95 | local mx,ip 96 | 97 | mx = results[i].exchange 98 | ip = results[i].ADDRESS.address or "(none)" 99 | 100 | print(mx,ip) 101 | end 102 | -------------------------------------------------------------------------------- /lua/test.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env lua 2 | -- ************************************************************************* 3 | -- 4 | -- Copyright 2010 by Sean Conner. All Rights Reserved. 5 | -- 6 | -- This library is free software; you can redistribute it and/or modify it 7 | -- under the terms of the GNU Lesser General Public License as published by 8 | -- the Free Software Foundation; either version 3 of the License, or (at your 9 | -- option) any later version. 10 | -- 11 | -- This library is distributed in the hope that it will be useful, but 12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 14 | -- License for more details. 15 | -- 16 | -- You should have received a copy of the GNU Lesser General Public License 17 | -- along with this library; if not, see . 18 | -- 19 | -- ************************************************************************** 20 | -- luacheck: ignore 611 21 | 22 | local SERVER = "127.0.0.1" 23 | local dns = require "org.conman.dns" 24 | 25 | -- ************************************************************** 26 | 27 | local function query(host,type) 28 | local e 29 | local r 30 | local err 31 | 32 | e,err = dns.encode { 33 | id = math.random(65535), 34 | query = true, 35 | rd = true, 36 | opcode = 'query', 37 | question = { 38 | name = host, 39 | type = type, 40 | class = 'in' 41 | } 42 | } 43 | 44 | if e == nil then 45 | return e,err 46 | end 47 | 48 | r,err = dns.query(SERVER,e) 49 | 50 | if r == nil then 51 | return r,err 52 | end 53 | 54 | return dns.decode(r) 55 | end 56 | 57 | -- **************************************************************** 58 | 59 | local function print_txt(rec) 60 | if type(rec.text) == 'string' then 61 | return string.format("%q",rec.text) 62 | elseif type(rec.text) == 'table' then 63 | local s = "(" 64 | for i = 1 , #rec.text do 65 | s = s .. string.format("\n\t\t\t%q",rec.text[i]) 66 | end 67 | s = s .. "\n\t\t)" 68 | return s 69 | else 70 | return "" 71 | end 72 | end 73 | 74 | local callbacks = 75 | { 76 | NS = function(rec) return rec.nsdname end, 77 | A = function(rec) return rec.address end, 78 | AAAA = function(rec) return rec.address end, 79 | CNAME = function(rec) return rec.cname end, 80 | MX = function(rec) return string.format("%5d %s",rec.preference,rec.exchange) end, 81 | PTR = function(rec) return rec.ptr end, 82 | HINFO = function(rec) return string.format("%q %q",rec.cpu,rec.os) end, 83 | SPF = print_txt, 84 | TXT = print_txt, 85 | SOA = function(rec) return string.format([[ 86 | %s %s ( 87 | %10d ; Serial 88 | %10d ; Refresh 89 | %10d ; Retry 90 | %10d ; Expire 91 | %10d ) ; Miminum 92 | ]], 93 | rec.mname, 94 | rec.rname, 95 | rec.serial, 96 | rec.refresh, 97 | rec.retry, 98 | rec.expire, 99 | rec.minimum ) end, 100 | NAPTR = function(rec) return string.format([[ 101 | %5d %5d ( 102 | %q 103 | %q 104 | %q 105 | %s ) 106 | ]], 107 | rec.order, 108 | rec.preference, 109 | rec.flags, 110 | rec.services, 111 | rec.regexp, 112 | rec.replacement) end, 113 | SRV = function(rec) return string.format( 114 | "%5d %5d %5d %s", 115 | rec.priority, 116 | rec.weight, 117 | rec.port, 118 | rec.target) end, 119 | LOC = function(rec) return string.format([[ 120 | ( 121 | %3d %2d %2d %s ; Latitude 122 | %3d %2d %2d %s ; Longitude 123 | %11d ; Altitude 124 | %11d ; Size 125 | %11d ; Horizontal Precision 126 | %11d ; Vertical Precision 127 | ) 128 | ]], 129 | rec.latitude.deg, 130 | rec.latitude.min, 131 | rec.latitude.sec, 132 | rec.latitude.hemisphere, 133 | rec.longitude.deg, 134 | rec.longitude.min, 135 | rec.longitude.sec, 136 | rec.longitude.hemisphere, 137 | rec.altitude, 138 | rec.size, 139 | rec.horiz_pre, 140 | rec.vert_pre ) end 141 | } 142 | 143 | local function print_answers(tag,recs) 144 | io.stdout:write(string.format("\n;;; %s\n\n",tag)) 145 | 146 | for i = 1 , #recs do 147 | local s = string.format("%-16s\t%d\t%s\t%s\t", 148 | recs[i].name, 149 | recs[i].ttl, 150 | recs[i].class, 151 | recs[i].type 152 | ) 153 | s = s .. callbacks[recs[i].type](recs[i]) .. "\n" 154 | io.stdout:write(s) 155 | end 156 | end 157 | 158 | -- ********************************************************************** 159 | 160 | 161 | if #arg == 0 then 162 | io.stderr:write(string.format("usage: %s type domain\n",arg[0])) 163 | os.exit(1) 164 | end 165 | 166 | local results,err 167 | 168 | results,err = query(arg[2],arg[1]) 169 | 170 | if results == nil then 171 | io.stderr:write(string.format( 172 | "error: query(%s,%s) = %s", 173 | arg[2], 174 | arg[1], 175 | err 176 | )) 177 | os.exit(1) 178 | end 179 | 180 | io.stdout:write(string.format([[ 181 | ; Questions = 1 182 | ; Answers = %d 183 | ; Name Servers = %d 184 | ; Additional Records = %d 185 | ; Authoritative Result = %s 186 | ; Truncated Result = %s 187 | ; Recursion Desired = %s 188 | ; Recursion Available = %s 189 | ; Result = %s 190 | 191 | ;;; QUESTIONS 192 | 193 | ; %s %s %s 194 | ]], 195 | #results.answers, 196 | #results.nameservers, 197 | #results.additional, 198 | tostring(results.aa), 199 | tostring(results.tc), 200 | tostring(results.rd), 201 | tostring(results.ra), 202 | results.rcode, 203 | results.question.name, 204 | results.question.class, 205 | results.question.type 206 | )) 207 | 208 | print_answers("ANSWERS" , results.answers) 209 | print_answers("NAMESERVERS" , results.nameservers) 210 | print_answers("ADDITIONAL" , results.additional) 211 | 212 | os.exit(0) 213 | -------------------------------------------------------------------------------- /notes: -------------------------------------------------------------------------------- 1 | https://www.netmeister.org/blog/https-rrs.html 2 | via https://lobste.rs/s/z5ogrr/use_https_resource_records 3 | 4 | 5 | https://www.netmeister.org/blog/tlds.html 6 | https://www.netmeister.org/blog/dns-rrs.html 7 | 8 | On avoiding malloc: 9 | 10 | http://spin.atomicobject.com/2012/11/01/hey-c-is-a-functional-language-too/ 11 | 12 | 13 | On Ruby bindings: 14 | 15 | http://onlamp.com/pub/a/onlamp/2004/11/18/extending_ruby.html 16 | 17 | --- 18 | 19 | Google: extending Ruby in C 20 | 21 | --- 22 | 23 | https://github.com/avsm/melange/blob/master/lib/dns/dns_rr.mpl 24 | 25 | http://www.bind9.net/dns-parameters 26 | 27 | -------------------------------------------------------------------------------- /org.conman.dns-2.1.3-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "org.conman.dns" 2 | version = "2.1.3-1" 3 | source = { 4 | url = "git+https://github.com/spc476/SPCDNS.git", 5 | tag = "v2.1.3" 6 | } 7 | description = { 8 | summary = "A Lua module to encode DNS queries and decode DNS answers.", 9 | detailed = [[ 10 | A simple interface to encode and decode DNS queries. This supports 11 | most of the commonly used DNS records and is meant to be a low level 12 | API upon which a generalized DNS query system can be built. 13 | ]], 14 | homepage = "http://www.conman.org/software/spcdns/", 15 | license = "LGPL", 16 | maintainer = "Sean Conner " 17 | } 18 | dependencies = { 19 | "lua >= 5.1, <= 5.4" 20 | } 21 | build = { 22 | type = "make", 23 | platforms = { 24 | linux = { 25 | build_variables = { 26 | CC = "gcc -std=c99" 27 | } 28 | }, 29 | solaris = { 30 | build_varaibles = { 31 | CC = "c99" 32 | } 33 | } 34 | }, 35 | build_target = "src/dns.so", 36 | build_variables = { 37 | CC = "$(CC)", 38 | CFLAGS = "$(CFLAGS) -I$(LUA_INCDIR)", 39 | LDSHARE = "$(LIBFLAG)", 40 | LUA = "$(LUA)" 41 | }, 42 | install_target = "install-lua", 43 | install_variables = { 44 | LIBDIR = "$(LIBDIR)", 45 | LUA = "$(LUA)" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/dns.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * Copyright 2010 by Sean Conner. All Rights Reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or (at your 8 | * option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, see . 17 | * 18 | **************************************************************************/ 19 | 20 | /************************************************************************* 21 | * 22 | * Definitions for all things related to the DNS protocol (and not to the 23 | * network transport thereof---that's for another episode). 24 | * 25 | * I've scoured the Internet and I think I've located every DNS RR type that 26 | * exists. And for the majority of them, I've made an in-memory 27 | * representation of said record for easy access to the contents (for when I 28 | * do get around to decoding them from their wire representation). For 29 | * records that I do not decode (and you'll need to check codec.c to see 30 | * which ones aren't being decoded) you'll get back a dns_x_t, which has the 31 | * common portion of the RR decoded (which includes the ID, type, class and 32 | * TTL) plus the remainder of the raw packet. 33 | * 34 | * My eventual intent is to decode those records that I can find definitions 35 | * for, and decipher the sometimes dry and dense RFCs that describe said RRs. 36 | * I'm well on my way with support for about half the known records (which 37 | * includes the ones most likely to be found in 99% of all zone files). 38 | * 39 | * This file assumes C99. You must include the following files before 40 | * including this one: 41 | * 42 | * #include 43 | * #include 44 | * #include 45 | * #incldue 46 | * 47 | ***************************************************************************/ 48 | 49 | #ifndef I_52281206_2176_5917_BC9C_574D81892362 50 | #define I_52281206_2176_5917_BC9C_574D81892362 51 | 52 | #include 53 | #include 54 | #if defined(_WIN32) 55 | # include 56 | # ifdef _MSC_VER 57 | # include 58 | # else 59 | # include 60 | # endif 61 | typedef uint32_t in_addr_t; 62 | #elif defined(__unix__) || defined (__APPLE__) 63 | # include 64 | #else 65 | // No platform implementation of in6_addr so we'll provide a simple one 66 | typedef uint32_t in_addr_t; 67 | struct in6_addr 68 | { 69 | union 70 | { 71 | uint8_t u6_addr8[16]; 72 | uint16_t u6_addr16[8]; 73 | uint32_t u6_addr32[4]; 74 | } in6_u; 75 | 76 | # define s6_addr in6_u.u6_addr8 77 | # define s6_addr16 in6_u.u6_addr16 78 | # define s6_addr32 in6_u.u6_addr32 79 | }; 80 | #endif 81 | 82 | #ifdef __cplusplus 83 | # define class dclass 84 | # define restrict 85 | extern "C" { 86 | #endif 87 | 88 | #ifndef __GNUC__ 89 | # define __attribute__(x) 90 | #endif 91 | 92 | /**************************************************************************** 93 | * Buffers passed to these routines should be declared as one of these two 94 | * types with one of the given sizes below, depending upon what the buffer is 95 | * being used for. This is to ensure things work out fine and don't blow up 96 | * (like a segfault). The 4K size *should* be okay for UDP packets, but if 97 | * you are worried, 8K is more than enough to handle responses from UDP. 98 | * Larger sizes may be required for TCP. 99 | * 100 | * A declaration would looke something like: 101 | * 102 | * dns_packet_t query_packet [DNS_BUFFER_UDP]; 103 | * dns_decoded_t decoded_response[DNS_DECODEBUF_4K]; 104 | * 105 | * Alternatively, you can do this: 106 | * 107 | * dns_packet_t *pquery_packet; 108 | * dns_decoded_t *pdecoded_response; 109 | * 110 | * pquery_packet = malloc(MAX_DNS_QUERY_SIZE); 111 | * pdecoded_response = malloc(4192); 112 | * 113 | *************************************************************************/ 114 | 115 | typedef uintptr_t dns_packet_t; 116 | typedef uintptr_t dns_decoded_t; 117 | 118 | #define DNS_BUFFER_UDP ( 512uL / sizeof(dns_packet_t)) 119 | #define DNS_BUFFER_UDP_MAX ( 1492uL / sizeof(dns_packet_t)) 120 | #define DNS_DECODEBUF_4K ( 4096uL / sizeof(dns_decoded_t)) 121 | #define DNS_DECODEBUF_8K ( 8192uL / sizeof(dns_decoded_t)) 122 | #define DNS_DECODEBUF_16k (16384uL / sizeof(dns_decoded_t)) 123 | 124 | /************************************************************************ 125 | * Various upper limits in the DNS protocol 126 | ************************************************************************/ 127 | 128 | #define MAX_DNS_QUERY_SIZE 512 129 | #define MAX_DOMAIN_SEGMENT 64 130 | #define MAX_DOMAIN_LABEL 64 131 | #define MAX_STRING_LEN 256 132 | #define MAX_UDP_PACKET_SIZE 1492 133 | 134 | /*************************************************************************** 135 | * I've specified where each RR, Class and error codes are defined. Also, 136 | * for the RRs, I've marked if I have decode support as well as experimental 137 | * and obsolete information as follows: 138 | * 139 | * + Encoding/Decoding support 140 | * O Obsolete 141 | * E Experimental 142 | * 143 | * https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml 144 | ***************************************************************************/ 145 | 146 | typedef enum dns_type 147 | { 148 | RR_A = 1, /* IPv4 Address + RFC-1035 */ 149 | RR_NS = 2, /* Name server + RFC-1035 */ 150 | RR_MD = 3, /* Mail Destination O+ RFC-1035 */ 151 | RR_MF = 4, /* Mail Forwarder O+ RFC-1035 */ 152 | RR_CNAME = 5, /* Canonical name + RFC-1035 */ 153 | RR_SOA = 6, /* Start of Authority + RFC-1035 */ 154 | RR_MB = 7, /* Mailbox E+ RFC-1035 */ 155 | RR_MG = 8, /* Mailgroup E+ RFC-1035 */ 156 | RR_MR = 9, /* Mailrename E+ RFC-1035 */ 157 | RR_NULL = 10, /* NULL resource E+ RFC-1035 */ 158 | RR_WKS = 11, /* Well Known Service + RFC-1035 */ 159 | RR_PTR = 12, /* Pointer + RFC-1035 */ 160 | RR_HINFO = 13, /* Host Info + RFC-1035 */ 161 | RR_MINFO = 14, /* Mailbox/mail list info + RFC-1035 */ 162 | RR_MX = 15, /* Mail Exchange + RFC-1035 */ 163 | RR_TXT = 16, /* Text + RFC-1035 */ 164 | RR_RP = 17, /* Responsible Person + RFC-1183 */ 165 | RR_AFSDB = 18, /* Andrew File System DB + RFC-1183 RFC-5864 */ 166 | RR_X25 = 19, /* X.25 address, route binding + RFC-1183 */ 167 | RR_ISDN = 20, /* ISDN address, route binding + RFC-1183 */ 168 | RR_RT = 21, /* Route Through + RFC-1183 */ 169 | RR_NSAP = 22, /* Network Service Access Proto + RFC-1348 RFC-1706 */ 170 | RR_NSAP_PTR = 23, /* NSAP Pointer + RFC-1348 */ 171 | RR_SIG = 24, /* Signature RFC-2065 RFC-2535 RFC-3755 RFC-4034 */ 172 | RR_KEY = 25, /* Key RFC-2065 RFC-2535 RFC-3755 RFC-4034 */ 173 | RR_PX = 26, /* X.400 mail mapping + RFC-2163 */ 174 | RR_GPOS = 27, /* Geographical position O+ RFC-1712 */ 175 | RR_AAAA = 28, /* IPv6 Address + RFC-1886 RFC-3596 */ 176 | RR_LOC = 29, /* Location + RFC-1876 */ 177 | RR_NXT = 30, /* Next RR RFC-2065 RFC-2535 RFC-3755 */ 178 | RR_EID = 31, /* Endpoint Identifier */ 179 | RR_NIMLOC = 32, /* Nimrod Locator */ 180 | RR_SRV = 33, /* Service + RFC-2782 */ 181 | RR_ATMA = 34, /* ATM Address */ 182 | RR_NAPTR = 35, /* Naming Authority Pointer + RFC-2168 RFC-2915 RFC-3403 */ 183 | RR_KX = 36, /* Key Exchange RFC-2230 */ 184 | RR_CERT = 37, /* Certification RFC-4398 */ 185 | RR_A6 = 38, /* IPv6 Address O RFC-2874 RFC-3658 */ 186 | RR_DNAME = 39, /* Non-terminal DNAME (IPv6) RFC-2672 */ 187 | RR_SINK = 40, /* Kitchen sink */ 188 | RR_OPT = 41, /* EDNS0 option (meta-RR) + RFC-2671 RFC-3225 RFC-6891 */ 189 | RR_APL = 42, /* Address Prefix List RFC-3123 */ 190 | RR_DS = 43, /* Delegation Signer RFC-3658 RFC-4034 */ 191 | RR_SSHFP = 44, /* SSH Key Fingerprint RFC-4255 */ 192 | RR_ISECKEY = 45, /* IP Security Key RFC-4025 */ 193 | RR_RRSIG = 46, /* Resource Record Signature RFC-3755 RFC-4034 */ 194 | RR_NSEC = 47, /* Next Security Record RFC-3755 RFC-4034 */ 195 | RR_DNSKEY = 48, /* DNS Security Key RFC-3755 RFC-4034 */ 196 | RR_DHCID = 49, /* DHCID RFC-4701 */ 197 | RR_NSEC3 = 50, /* NSEC3 RFC-5155 */ 198 | RR_NSEC3PARAM = 51, /* NSEC3PARAM RFC-5155 */ 199 | RR_TLSA = 52, /* TLSA RFC-6698 */ 200 | RR_SMIMEA = 53, /* S/MIME cert association RFC-8162 */ 201 | RR_HIP = 55, /* Host Identity Protocol RFC-5205 */ 202 | RR_NINFO = 56, /* NINFO */ 203 | RR_RKEY = 57, /* RKEY */ 204 | RR_TALINK = 58, /* Trust Anchor Link */ 205 | RR_CDS = 59, /* Child DS RFC-7344 */ 206 | RR_CDNSKEY = 60, /* DNSKEY the Child wants reflected RFC-7344 */ 207 | RR_OPENPGPKEY = 61, /* OpenPGP key RFC-7929 */ 208 | RR_CSYNC = 62, /* Child-to-Parent Synchronization RFC-7477 */ 209 | RR_ZONEMD = 63, /* Message Digest Over Zone Data RFC-8976 */ 210 | RR_SVCB = 64, /* Service Binding */ 211 | RR_HTTPS = 65, /* HTTPS Binding (really?) */ 212 | RR_SPF = 99, /* Sender Policy Framework O+ RFC-4408 RFC-7208 */ 213 | RR_UINFO = 100, /* IANA Reserved */ 214 | RR_UID = 101, /* IANA Reserved */ 215 | RR_GID = 102, /* IANA Reserved */ 216 | RR_UNSPEC = 103, /* IANA Reserved */ 217 | RR_NID = 104, /* Node Identifier RFC-6742 */ 218 | RR_L32 = 105, /* 32-bit Locator value RFC-6742 */ 219 | RR_L64 = 106, /* 64-bit Locator value RFC-6742 */ 220 | RR_LP = 107, /* Name of ILNP subnetwork RFC-6742 */ 221 | RR_EUI48 = 108, /* EUI-48 address RFC-7043 */ 222 | RR_EUI64 = 109, /* EUI-64 address RFC-7043 */ 223 | 224 | /* Query types, >= 128 */ 225 | 226 | RR_TKEY = 249, /* Transaction Key RFC-2930 */ 227 | RR_TSIG = 250, /* Transaction Signature RFC-2845 */ 228 | RR_IXFR = 251, /* Incremental zone transfer RFC-1995 */ 229 | RR_AXFR = 252, /* Transfer of zone RFC-1035 RFC-5936 */ 230 | RR_MAILB = 253, /* Mailbox related records RFC-1035 */ 231 | RR_MAILA = 254, /* Mail agent RRs (obsolete) O RFC-1035 */ 232 | RR_ANY = 255, /* All records RFC-1035 RFC-6895 RFC-8482 */ 233 | RR_URI = 256, /* Universal Resource Indicator RFC-7553 */ 234 | RR_CAA = 257, /* Certification Authority Restriction RFC-8659 */ 235 | RR_AVC = 258, /* Application Visibility and Control */ 236 | RR_DOA = 259, /* Digital Object Architecture */ 237 | RR_AMTRELAY = 260, /* Automatic Multicast Tunneling Relay RFC-8777 */ 238 | 239 | RR_TA = 32768, /* DNSSEC Trust Authories */ 240 | RR_DLV = 32769, /* DNSSEC Lookaside Validation O RFC-8749 RFC-4431 */ 241 | 242 | RR_PRIVATE = 65280, /* Private usage RFC-2929 */ 243 | RR_UNKNOWN = 65535, /* Unknown record type RFC-6895 */ 244 | } dns_type_t; 245 | 246 | typedef enum edns0_type 247 | { 248 | EDNS0RR_NSID = 3 /* Name Server ID + RFC-5001 */ 249 | } edns0_type_t; 250 | 251 | typedef enum dns_class 252 | { 253 | CLASS_IN = 1, /* Internet RFC-1035 */ 254 | CLASS_CS = 2, /* CSNET (obsolete) RFC-1035 */ 255 | CLASS_CH = 3, /* CHAOS RFC-1035 */ 256 | CLASS_HS = 4, /* Hesiod RFC-1035 */ 257 | CLASS_NONE = 254, /* RFC-2136 */ 258 | CLASS_ANY = 255, /* All classes RFC-1035 */ 259 | CLASS_PRIVATE = 65280, /* Private use RFC-2929 */ 260 | CLASS_UNKNOWN = 65535, /* Unknown class RFC-2929 */ 261 | } dns_class_t; 262 | 263 | typedef enum dns_op 264 | { 265 | OP_QUERY = 0, /* RFC-1035 */ 266 | OP_IQUERY = 1, /* RFC-1035 RFC-3425 */ /* Obsolete */ 267 | OP_STATUS = 2, /* RFC-1035 */ 268 | OP_NOTIFY = 4, /* RFC-1996 */ 269 | OP_UPDATE = 5, /* RFC-2136 */ 270 | OP_UNKNOWN = 1 /* Since OP_IQUERY is obsolete */ 271 | } dns_op_t; 272 | 273 | typedef enum dns_rcode 274 | { 275 | RCODE_OKAY = 0, /* RFC-1035 */ 276 | RCODE_FORMAT_ERROR = 1, /* RFC-1035 */ 277 | RCODE_SERVER_FAILURE = 2, /* RFC-1035 */ 278 | RCODE_NAME_ERROR = 3, /* RFC-1035 */ 279 | RCODE_NOT_IMPLEMENTED = 4, /* RFC-1035 */ 280 | RCODE_REFUSED = 5, /* RFC-1035 */ 281 | RCODE_YXDOMAIN = 6, /* RFC-2136 */ 282 | RCODE_YXRRSET = 7, /* RFC-2136 */ 283 | RCODE_NXRRSET = 8, /* RFC-2136 */ 284 | RCODE_NOTAUTH = 9, /* RFC-2136 */ 285 | RCODE_NOTZONE = 10, /* RFC-2136 */ 286 | RCODE_BADVERS = 16, /* RFC-2671 */ 287 | RCODE_BADSIG = 16, /* RFC-2845 */ 288 | RCODE_BADKEY = 17, /* RFC-2845 */ 289 | RCODE_BADTIME = 18, /* RFC-2845 */ 290 | RCODE_BADMODE = 19, /* RFC-2845 */ 291 | RCODE_BADNAME = 20, /* RFC-2930 */ 292 | RCODE_BADALG = 21, /* RFC-2930 */ 293 | RCODE_BADTRUC = 22, /* RFC-4635 */ 294 | RCODE_BADCOOKIE = 23, /* RFC-7873 */ 295 | RCODE_PRIVATE = 3841, /* RFC-2929 */ 296 | 297 | RCODE_NO_MEMORY, 298 | RCODE_BAD_STRING, 299 | } dns_rcode_t; 300 | 301 | typedef enum edns0_label 302 | { 303 | EDNS0_ELT = 0x01, /* RFC-2673 (experimental RFC-3363) */ 304 | EDNS0_RSVP = 0x3F /* RFC-2671 */ 305 | } edns0_label_t; 306 | 307 | typedef uint32_t TTL; 308 | 309 | typedef struct dns_question_t /* RFC-1035 */ 310 | { 311 | char const *name; 312 | dns_type_t type; 313 | dns_class_t class; 314 | } dns_question_t; 315 | 316 | typedef struct dns_generic_t /* RFC-1035 */ 317 | { 318 | char const *name; 319 | dns_type_t type; 320 | dns_class_t class; 321 | TTL ttl; 322 | } dns_generic_t; 323 | 324 | typedef struct dns_a_t /* RFC-1035 */ 325 | { 326 | char const *name; 327 | dns_type_t type; 328 | dns_class_t class; 329 | TTL ttl; 330 | in_addr_t address; 331 | } dns_a_t; 332 | 333 | typedef struct dns_ns_t /* RFC-1035 */ 334 | { 335 | char const *name; 336 | dns_type_t type; 337 | dns_class_t class; 338 | TTL ttl; 339 | char const *nsdname; 340 | } dns_ns_t; 341 | 342 | typedef struct dns_md_t /* RFC-1035 */ 343 | { 344 | char const *name; 345 | dns_type_t type; 346 | dns_class_t class; 347 | TTL ttl; 348 | char const *madname; 349 | } dns_md_t; 350 | 351 | typedef struct dns_mf_t /* RFC-1035 */ 352 | { 353 | char const *name; 354 | dns_type_t type; 355 | dns_class_t class; 356 | TTL ttl; 357 | char const *madname; 358 | } dns_mf_t; 359 | 360 | typedef struct dns_cname_t /* RFC-1035 */ 361 | { 362 | char const *name; 363 | dns_type_t type; 364 | dns_class_t class; 365 | TTL ttl; 366 | char const *cname; 367 | } dns_cname_t; 368 | 369 | typedef struct dns_soa_t /* RFC-1035 */ 370 | { 371 | char const *name; 372 | dns_type_t type; 373 | dns_class_t class; 374 | TTL ttl; 375 | char const *mname; 376 | char const *rname; 377 | uint32_t serial; 378 | uint32_t refresh; 379 | uint32_t retry; 380 | uint32_t expire; 381 | uint32_t minimum; 382 | } dns_soa_t; 383 | 384 | typedef struct dns_mb_t /* RFC-1035 */ 385 | { 386 | char const *name; 387 | dns_type_t type; 388 | dns_class_t class; 389 | TTL ttl; 390 | char const *madname; 391 | } dns_mb_t; 392 | 393 | typedef struct dns_mg_t /* RFC-1035 */ 394 | { 395 | char const *name; 396 | dns_type_t type; 397 | dns_class_t class; 398 | TTL ttl; 399 | char const *mgmname; 400 | } dns_mg_t; 401 | 402 | typedef struct dns_mr_t /* RFC-1035 */ 403 | { 404 | char const *name; 405 | dns_type_t type; 406 | dns_class_t class; 407 | TTL ttl; 408 | char const *newname; 409 | } dns_mr_t; 410 | 411 | typedef struct dns_null_t /* RFC-1035 */ 412 | { 413 | char const *name; 414 | dns_type_t type; 415 | dns_class_t class; 416 | TTL ttl; 417 | size_t size; 418 | uint8_t *data; 419 | } dns_null_t; 420 | 421 | typedef struct dns_wks_t /* RFC-1035 */ 422 | { 423 | char const *name; 424 | dns_type_t type; 425 | dns_class_t class; 426 | TTL ttl; 427 | in_addr_t address; 428 | int protocol; 429 | size_t numbits; /* <= 8192 */ 430 | uint8_t *bits; 431 | } dns_wks_t; 432 | 433 | typedef struct dns_ptr_t /* RFC-1035 */ 434 | { 435 | char const *name; 436 | dns_type_t type; 437 | dns_class_t class; 438 | TTL ttl; 439 | char const *ptr; 440 | } dns_ptr_t; 441 | 442 | typedef struct dns_hinfo_t /* RFC-1035 */ 443 | { 444 | char const *name; 445 | dns_type_t type; 446 | dns_class_t class; 447 | TTL ttl; 448 | char const *cpu; 449 | char const *os; 450 | } dns_hinfo_t; 451 | 452 | typedef struct dns_minfo_t /* RFC-1035 */ 453 | { 454 | char const *name; 455 | dns_type_t type; 456 | dns_class_t class; 457 | TTL ttl; 458 | char const *rmailbx; 459 | char const *emailbx; 460 | } dns_minfo_t; 461 | 462 | typedef struct dns_mx_t /* RFC-1035 */ 463 | { 464 | char const *name; 465 | dns_type_t type; 466 | dns_class_t class; 467 | TTL ttl; 468 | int preference; 469 | char const *exchange; 470 | } dns_mx_t; 471 | 472 | typedef struct dns_txt_t /* RFC-1035 */ 473 | { 474 | char const *name; 475 | dns_type_t type; 476 | dns_class_t class; 477 | TTL ttl; 478 | size_t len; 479 | char const *text; 480 | } dns_txt_t; 481 | 482 | typedef struct dns_rp_t /* RFC-1183 */ 483 | { 484 | char const *name; 485 | dns_type_t type; 486 | dns_class_t class; 487 | TTL ttl; 488 | char const *mbox; 489 | char const *domain; 490 | } dns_rp_t; 491 | 492 | typedef struct dns_afsdb_t /* RFC-1183 */ 493 | { 494 | char const *name; 495 | dns_type_t type; 496 | dns_class_t class; 497 | TTL ttl; 498 | int subtype; 499 | char const *hostname; 500 | } dns_afsdb_t; 501 | 502 | typedef struct dns_x25_t /* RFC-1183 */ 503 | { 504 | char const *name; 505 | dns_type_t type; 506 | dns_class_t class; 507 | TTL ttl; 508 | size_t size; 509 | char const *psdnaddress; 510 | } dns_x25_t; 511 | 512 | typedef struct dns_isdn_t /* RFC-1183 */ 513 | { 514 | char const *name; 515 | dns_type_t type; 516 | dns_class_t class; 517 | TTL ttl; 518 | char const *isdnaddress; 519 | char const *sa; 520 | } dns_isdn_t; 521 | 522 | typedef struct dns_rt_t /* RFC-1183 */ 523 | { 524 | char const *name; 525 | dns_type_t type; 526 | dns_class_t class; 527 | TTL ttl; 528 | int preference; 529 | char const *host; 530 | } dns_rt_t; 531 | 532 | typedef struct dns_nsap_t /* RFC-1348 */ 533 | { 534 | char const *name; 535 | dns_type_t type; 536 | dns_class_t class; 537 | TTL ttl; 538 | char const *length; 539 | char const *nsapaddress; 540 | } dns_nsap_t; 541 | 542 | typedef struct dns_nsap_ptr_t /* RFC-1348 */ 543 | { 544 | char const *name; 545 | dns_type_t type; 546 | dns_class_t class; 547 | TTL ttl; 548 | char const *owner; 549 | } dns_nsap_ptr_t; 550 | 551 | typedef enum dnskey_algorithm /* RFC-2065 */ 552 | { 553 | DNSKEYA_RSAMD5 = 1, 554 | DNSKEYA_DH = 2, /* RFC-2535 */ 555 | DNSKEYA_DSA = 3, /* RFC-2535 */ 556 | DNSKEYA_ECC = 4, /* RFC-2535 */ 557 | DNSKEYA_RSASHA1 = 5, /* RFC-3110 */ 558 | DNSKEYA_INDIRECT = 252, /* RFC-2535 */ 559 | DNSKEYA_PRIVATEDNS = 253, 560 | DNSKEYA_PRIVATEOID = 254, 561 | DNSKEYA_RSVP = 255 562 | } dnskey_algorithm; 563 | 564 | typedef struct dns_sig_t /* RFC-2065 */ 565 | { 566 | char const *name; 567 | dns_type_t type; 568 | dns_class_t class; 569 | TTL ttl; 570 | dns_type_t covered; 571 | dnskey_algorithm algorithm; 572 | int labels; 573 | TTL originttl; 574 | unsigned long sigexpire; 575 | unsigned long timesigned; 576 | uint16_t keyfootprint; 577 | char const *signer; 578 | size_t sigsize; 579 | uint8_t *signature; 580 | } dns_sig_t; 581 | 582 | typedef enum dnskey_protocol /* RFC-2535 */ 583 | { 584 | DNSKEYP_NONE = 0, 585 | DNSKEYP_TLS = 1, 586 | DNSKEYP_EMAIL = 2, 587 | DNSKEYP_DNSSEC = 3, 588 | DNSKEYP_IPSEC = 4, 589 | DNSKEYP_ALL = 255 590 | } dnskey_protocol; 591 | 592 | typedef union dnskey_key /* RFC-2065 */ 593 | { 594 | struct 595 | { 596 | size_t expsize; 597 | uint8_t *exponent; 598 | size_t modsize; 599 | uint8_t *modulus; 600 | } md5; 601 | 602 | struct 603 | { 604 | size_t size; 605 | uint8_t *data; 606 | } unknown; 607 | } dnskey_key; 608 | 609 | typedef struct dns_key_t /* RFC-2065 */ 610 | { 611 | char const *name; 612 | dns_type_t type; 613 | dns_class_t class; 614 | TTL ttl; 615 | struct 616 | { 617 | bool authentication; 618 | bool confidential; 619 | bool experimental; 620 | bool user; 621 | bool zone; 622 | bool host; 623 | bool ipsec; 624 | bool email; /* not in RFC-2535 */ 625 | } flags; 626 | int signatory; 627 | dnskey_protocol protocol; 628 | dnskey_algorithm algorithm; 629 | dnskey_key key; 630 | } dns_key_t; 631 | 632 | typedef struct dns_px_t /* RFC-2163 */ 633 | { 634 | char const *name; 635 | dns_type_t type; 636 | dns_class_t class; 637 | TTL ttl; 638 | char const *map822; 639 | char const *mapx400; 640 | } dns_px_t; 641 | 642 | typedef struct dnsgpos_angle /* RFC-1712 , RFC1876 */ 643 | { 644 | int deg; 645 | int min; 646 | int sec; 647 | int frac; 648 | bool nw; /* Northern or Western Hemisphere */ 649 | } dnsgpos_angle; 650 | 651 | typedef struct dns_gpos_t /* RFC-1712 */ 652 | { 653 | char const *name; 654 | dns_type_t type; 655 | dns_class_t class; 656 | TTL ttl; 657 | dnsgpos_angle longitude; 658 | dnsgpos_angle latitude; 659 | double altitude; 660 | } dns_gpos_t; 661 | 662 | typedef struct dns_aaaa_t /* RFC-1886 */ 663 | { 664 | char const *name; 665 | dns_type_t type; 666 | dns_class_t class; 667 | TTL ttl; 668 | struct in6_addr address; 669 | } dns_aaaa_t; 670 | 671 | typedef struct dns_loc_t /* RFC-1876 */ 672 | { 673 | char const *name; 674 | dns_type_t type; 675 | dns_class_t class; 676 | TTL ttl; 677 | int version; 678 | unsigned long long size; /* plese see RFC-1876 for a discussion */ 679 | unsigned long long horiz_pre; /* of these fields */ 680 | unsigned long long vert_pre; 681 | dnsgpos_angle latitude; 682 | dnsgpos_angle longitude; 683 | long altitude; 684 | } dns_loc_t; 685 | 686 | typedef struct dns_nxt_t /* RFC-2065 */ 687 | { 688 | char const *name; 689 | dns_type_t type; 690 | dns_class_t class; 691 | TTL ttl; 692 | char const *next; 693 | size_t numbits; 694 | uint8_t *bitmap; 695 | } dns_nxt_t; 696 | 697 | typedef struct dns_eid_t /* (unknown) */ 698 | { 699 | char const *name; 700 | dns_type_t type; 701 | dns_class_t class; 702 | TTL ttl; 703 | size_t size; 704 | uint8_t *rawdata; 705 | } dns_eid_t; 706 | 707 | typedef struct dns_nimloc_t /* (unknown) */ 708 | { 709 | char const *name; 710 | dns_type_t type; 711 | dns_class_t class; 712 | TTL ttl; 713 | size_t size; 714 | uint8_t *rawdata; 715 | } dns_nimloc_t; 716 | 717 | typedef struct dns_srv_t /* RFC-2782 */ 718 | { 719 | char const *name; 720 | dns_type_t type; 721 | dns_class_t class; 722 | TTL ttl; 723 | int priority; 724 | int weight; 725 | int port; 726 | char const *target; 727 | } dns_srv_t; 728 | 729 | typedef struct dns_atm_t /* (unknown) */ 730 | { 731 | char const *name; 732 | dns_type_t type; 733 | dns_class_t class; 734 | TTL ttl; 735 | size_t size; 736 | uint8_t *rawdata; 737 | } dns_atm_t; 738 | 739 | typedef struct dns_naptr_t /* RFC-2915 */ 740 | { 741 | char const *name; 742 | dns_type_t type; 743 | dns_class_t class; 744 | TTL ttl; 745 | int order; 746 | int preference; 747 | char const *flags; 748 | char const *services; 749 | char const *regexp; 750 | char const *replacement; 751 | } dns_naptr_t; 752 | 753 | typedef struct dns_kx_t /* (unknown) */ 754 | { 755 | char const *name; 756 | dns_type_t type; 757 | dns_class_t class; 758 | TTL ttl; 759 | size_t size; 760 | uint8_t *rawdata; 761 | } dns_kx_t; 762 | 763 | typedef struct dns_cert_t /* (unknown) */ 764 | { 765 | char const *name; 766 | dns_type_t type; 767 | dns_class_t class; 768 | TTL ttl; 769 | size_t size; 770 | uint8_t *rawdata; 771 | } dns_cert_t; 772 | 773 | typedef struct dns_a6_t /* RFC-2874 */ 774 | { 775 | char const *name; 776 | dns_type_t type; 777 | dns_class_t class; 778 | TTL ttl; 779 | size_t mask; 780 | struct in6_addr address; 781 | char const *prefixname; 782 | } dns_a6_t; 783 | 784 | typedef struct dns_dname_t /* RFC-2672 */ 785 | { 786 | char const *name; 787 | dns_type_t type; 788 | dns_class_t class; 789 | TTL ttl; 790 | size_t size; 791 | uint8_t *rawdata; 792 | } dns_dname_t; 793 | 794 | typedef struct dns_sink_t /* (unknown) */ 795 | { 796 | char const *name; 797 | dns_type_t type; 798 | dns_class_t class; 799 | TTL ttl; 800 | size_t size; 801 | uint8_t *rawdata; 802 | } dns_sink_t; 803 | 804 | typedef struct edns0_opt_t /* RFC-2671 */ 805 | { 806 | edns0_type_t code; /* 0 <= code <= UINT16_MAX */ 807 | size_t len; /* 0 <= len <= UINT16_MAX */ 808 | uint8_t *data; /* encoded per RFC specification */ 809 | } edns0_opt_t; 810 | 811 | typedef struct dns_edns0opt_t /* RFC-2671 */ 812 | { 813 | char const *name; 814 | dns_type_t type; 815 | dns_class_t class; /* not applicable --- set to CLASS_UNKNOWN */ 816 | TTL ttl; /* not applicable --- set to 0 */ 817 | size_t udp_payload; 818 | int version; 819 | bool fdo; /* RFC-3225 */ 820 | int fug; 821 | unsigned int z; /* should be zero */ 822 | size_t numopts; 823 | edns0_opt_t *opts; 824 | } dns_edns0opt_t; 825 | 826 | typedef struct dnsapl_record /* RFC-3123 */ 827 | { 828 | int addressfamily; 829 | int prefix; 830 | size_t afdlength; 831 | uint8_t *afdpart; 832 | bool negate; 833 | } dnsapl_record; 834 | 835 | typedef struct dns_apl_t /* RFC-3123 */ 836 | { 837 | char const *name; 838 | dns_type_t type; 839 | dns_class_t class; 840 | TTL ttl; 841 | size_t numrecs; 842 | dnsapl_record *recs; 843 | } dns_apl_t; 844 | 845 | 846 | typedef enum dnsds_digest /* RFC-3658 */ 847 | { 848 | DNSDS_SHA1 = 1 849 | } dnsds_digest; 850 | 851 | typedef struct dns_ds_t /* RFC-3658 */ 852 | { 853 | char const *name; 854 | dns_type_t type; 855 | dns_class_t class; 856 | TTL ttl; 857 | dnskey_protocol keytag; 858 | dnskey_algorithm algorithm; 859 | dnsds_digest digest; 860 | size_t digestlen; 861 | uint8_t *digestdata; 862 | } dns_ds_t; 863 | 864 | typedef struct dns_rrsig_t /* RFC-4034 */ 865 | { 866 | char const *name; 867 | dns_type_t type; 868 | dns_class_t class; 869 | TTL ttl; 870 | dns_type_t covered; 871 | dnskey_algorithm algorithm; 872 | int labels; 873 | TTL originttl; 874 | unsigned long sigexpire; 875 | unsigned long timesigned; 876 | uint16_t keyfootprint; 877 | char const *signer; 878 | size_t sigsize; 879 | uint8_t *signature; 880 | } dns_rrsig_t; 881 | 882 | typedef struct dns_nsec_t /* RFC-4034 */ 883 | { 884 | char const *name; 885 | dns_type_t type; 886 | dns_class_t class; 887 | TTL ttl; 888 | char const *next; 889 | size_t numbits; 890 | uint8_t *bitmap; 891 | } dns_nsec_t; 892 | 893 | typedef struct dns_dnskey_t /* RFC-4034 */ 894 | { 895 | char const *name; 896 | dns_type_t type; 897 | dns_class_t class; 898 | TTL ttl; 899 | bool zonekey; 900 | bool sep; 901 | dnskey_protocol protocol; /* must be DNSKEYP_DNSSEC */ 902 | dnskey_algorithm algorithm; 903 | size_t keysize; 904 | uint8_t *key; 905 | } dns_dnskey_t; 906 | 907 | typedef struct dns_sshfp_t /* RFC-4255 */ 908 | { 909 | char const *name; 910 | dns_type_t type; 911 | dns_class_t class; 912 | TTL ttl; 913 | dnskey_algorithm algorithm; 914 | dnsds_digest fptype; 915 | size_t fpsize; 916 | uint8_t *fingerprint; 917 | } dns_sshfp_t; 918 | 919 | typedef struct dns_spf_t /* RFC-4408 */ 920 | { 921 | char const *name; 922 | dns_type_t type; 923 | dns_class_t class; 924 | TTL ttl; 925 | size_t len; 926 | char const *text; 927 | } dns_spf_t; 928 | 929 | typedef struct dns_tsig_t /* RFC-2845 */ 930 | { 931 | char const *name; 932 | dns_type_t type; 933 | dns_class_t class; 934 | TTL ttl; /* must be 0 */ 935 | char const *algorithm; 936 | uint64_t timesigned; 937 | unsigned int fudge; 938 | size_t MACsize; 939 | uint8_t *MAC; 940 | int id; 941 | int error; 942 | size_t lenother; 943 | uint8_t *other; 944 | } dns_tsig_t; 945 | 946 | typedef struct dns_x_t /* CATCH-ALL */ 947 | { 948 | char const *name; 949 | dns_type_t type; 950 | dns_class_t class; 951 | TTL ttl; 952 | size_t size; 953 | uint8_t *rawdata; 954 | } dns_x_t; 955 | 956 | typedef union dns_answer_t 957 | { 958 | dns_generic_t generic; 959 | dns_x_t x; 960 | dns_a_t a; 961 | dns_ns_t ns; 962 | dns_md_t md; 963 | dns_mf_t mf; 964 | dns_cname_t cname; 965 | dns_soa_t soa; 966 | dns_mb_t mb; 967 | dns_mg_t mg; 968 | dns_mr_t mr; 969 | dns_null_t null; 970 | dns_wks_t wks; 971 | dns_ptr_t ptr; 972 | dns_hinfo_t hinfo; 973 | dns_minfo_t minfo; 974 | dns_mx_t mx; 975 | dns_txt_t txt; 976 | dns_rp_t rp; 977 | dns_afsdb_t afsdb; 978 | dns_x25_t x25; 979 | dns_isdn_t isdn; 980 | dns_rt_t rt; 981 | dns_nsap_t nsap; 982 | dns_nsap_ptr_t nsap_ptr; 983 | dns_sig_t sig; 984 | dns_key_t key; 985 | dns_px_t px; 986 | dns_gpos_t gpos; 987 | dns_aaaa_t aaaa; 988 | dns_loc_t loc; 989 | dns_nxt_t nxt; 990 | dns_eid_t eid; 991 | dns_nimloc_t nimloc; 992 | dns_srv_t srv; 993 | dns_atm_t atm; 994 | dns_naptr_t naptr; 995 | dns_kx_t kx; 996 | dns_cert_t cert; 997 | dns_a6_t a6; 998 | dns_dname_t dname; 999 | dns_sink_t sink; 1000 | dns_edns0opt_t opt; 1001 | dns_apl_t apl; 1002 | dns_ds_t ds; 1003 | dns_rrsig_t rrsig; 1004 | dns_nsec_t nsec; 1005 | dns_dnskey_t dnskey; 1006 | dns_spf_t spf; 1007 | dns_tsig_t tsig; 1008 | } dns_answer_t; 1009 | 1010 | typedef struct dns_query_t /* RFC-1035 */ 1011 | { 1012 | int id; 1013 | bool query; 1014 | dns_op_t opcode; 1015 | bool aa; 1016 | bool tc; 1017 | bool rd; 1018 | bool ra; 1019 | bool z; /* should be zero */ 1020 | bool ad; /* RFC-2065 */ 1021 | bool cd; /* RFC-2065 */ 1022 | dns_rcode_t rcode; 1023 | size_t qdcount; 1024 | size_t ancount; 1025 | size_t nscount; 1026 | size_t arcount; 1027 | dns_question_t *questions; 1028 | dns_answer_t *answers; 1029 | dns_answer_t *nameservers; 1030 | dns_answer_t *additional; 1031 | } dns_query_t; 1032 | 1033 | /**********************************************************************/ 1034 | 1035 | extern dns_rcode_t dns_encode(dns_packet_t *,size_t *,const dns_query_t *) __attribute__ ((nothrow,nonnull)); 1036 | extern dns_rcode_t dns_decode(dns_decoded_t *,size_t *,const dns_packet_t *,size_t) __attribute__ ((nothrow,nonnull(1,2,3))); 1037 | 1038 | #ifdef __cplusplus 1039 | } 1040 | # undef class 1041 | # undef restrict 1042 | #endif 1043 | #endif 1044 | -------------------------------------------------------------------------------- /src/dotest.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * Copyright 2010 by Sean Conner. All Rights Reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or (at your 8 | * option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, see . 17 | * 18 | **************************************************************************/ 19 | 20 | /********************************************************************** 21 | * 22 | * Sample application using my DNS library. It's somewhat similar to dig, 23 | * but lacking features found in dig. Still useful though, and gives an 24 | * example of how to use the DNS library. 25 | * 26 | * This code is C99. 27 | * 28 | ***************************************************************************/ 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | 36 | #include "dns.h" 37 | #include "mappings.h" 38 | #include "netsimple.h" 39 | #include "output.h" 40 | 41 | enum 42 | { 43 | OPT_NONE = '\0', 44 | OPT_HELP = 'h', 45 | OPT_EDNS = 'e', 46 | OPT_SERVER = 's', 47 | OPT_DUMP = 'd', 48 | OPT_ERR = '?' 49 | }; 50 | 51 | /************************************************************************/ 52 | 53 | static void usage (const char *); 54 | 55 | /************************************************************************/ 56 | 57 | const struct option c_options[] = 58 | { 59 | { "server" , required_argument , NULL , OPT_SERVER } , 60 | { "edns" , no_argument , NULL , OPT_EDNS } , 61 | { "dump" , no_argument , NULL , OPT_DUMP } , 62 | { "help" , no_argument , NULL , OPT_HELP } , 63 | { NULL , 0 , NULL , 0 } 64 | }; 65 | 66 | /***********************************************************************/ 67 | 68 | int main(int argc,char *argv[]) 69 | { 70 | const char *serverhost; 71 | const char *host; 72 | const char *type; 73 | bool fdump; 74 | bool fedns; 75 | int option; 76 | int rc; 77 | 78 | /*------------------------------------------------------------------------- 79 | ; verbiage to parse the command line and set some sane defaults, yada yada 80 | ; blah blah blah 81 | ;------------------------------------------------------------------*/ 82 | 83 | serverhost = "127.0.0.1"; 84 | host = "example.net"; 85 | type = "A"; 86 | fdump = false; 87 | fedns = false; 88 | option = 0; 89 | opterr = 0; /* prevent getopt_long() from printing error messages */ 90 | 91 | while(true) 92 | { 93 | rc = getopt_long(argc,argv,"hdes:",c_options,&option); 94 | if (rc == EOF) break; 95 | 96 | switch(rc) 97 | { 98 | default: 99 | case OPT_ERR: 100 | fprintf(stderr,"unknown option '%c'\n",optopt); 101 | case OPT_HELP: 102 | usage(argv[0]); 103 | return EXIT_FAILURE; 104 | case OPT_SERVER: 105 | serverhost = optarg; 106 | break; 107 | case OPT_EDNS: 108 | fedns = true; 109 | break; 110 | case OPT_DUMP: 111 | fdump = true; 112 | break; 113 | case OPT_NONE: 114 | break; 115 | } 116 | } 117 | 118 | if (optind == argc) 119 | { 120 | usage(argv[0]); 121 | return EXIT_FAILURE; 122 | } 123 | 124 | host = argv[optind++]; 125 | 126 | if (optind < argc) 127 | type = argv[optind]; 128 | 129 | /*------------------------------------------------------------------------ 130 | ; Encoding of a DNS query. I'm finding that many (if not all) DNS servers 131 | ; only accept a single question, even though the protocol seems to allow 132 | ; more than one question. If there *is* a DNS server that can handle 133 | ; multiple questions, then we can handle them, even if they don't exist 134 | ; yet. 135 | ;--------------------------------------------------------------------*/ 136 | 137 | dns_question_t domain; 138 | dns_query_t query; 139 | dns_packet_t request[DNS_BUFFER_UDP]; 140 | size_t reqsize; 141 | edns0_opt_t opt; 142 | dns_answer_t edns; 143 | 144 | domain.name = host; 145 | domain.type = dns_type_value(type); 146 | domain.class = CLASS_IN; 147 | 148 | query.id = 1234; /* should be a random value */ 149 | query.query = true; 150 | query.opcode = OP_QUERY; 151 | query.aa = false; 152 | query.tc = false; 153 | query.rd = true; 154 | query.ra = false; 155 | query.z = false; 156 | query.ad = false; 157 | query.cd = false; 158 | query.rcode = RCODE_OKAY; 159 | query.qdcount = 1; 160 | query.questions = &domain; 161 | query.ancount = 0; 162 | query.answers = NULL; 163 | query.nscount = 0; 164 | query.nameservers = NULL; 165 | query.arcount = 0; 166 | query.additional = NULL; 167 | 168 | if (fedns) 169 | { 170 | /*---------------------------------------------------------------------- 171 | ; Test EDNS0 by sending an NSID OPT RR type query. 172 | ; 173 | ; The udp_payload is the largest UDP packet we can reasonably expect to 174 | ; receive. I'm using the value 1464 since that's about the largest UDP 175 | ; packet that can fit into an Ethernet frame (20 bytes IP header, 8 176 | ; bytes UDP header; RFC-1042 based Ethernet frame). 177 | ; 178 | ; Additionally, OPT RRs *MUST* be in the additional section of a DNS 179 | ; packet, and there can be only one (Highlander 2 & 3? Never happened; 180 | ; neither did the TV series) OPT RR. 181 | ;----------------------------------------------------------------------*/ 182 | 183 | opt.code = EDNS0RR_NSID; 184 | opt.data = (uint8_t *)"MY-DNS-SERVER-ID"; 185 | opt.len = strlen((char *)opt.data); 186 | 187 | edns.opt.name = "."; 188 | edns.opt.type = RR_OPT; 189 | edns.opt.class = CLASS_UNKNOWN; 190 | edns.opt.ttl = 0; 191 | edns.opt.udp_payload = 1464; 192 | edns.opt.version = 0; 193 | edns.opt.fdo = false; 194 | edns.opt.z = 0; 195 | edns.opt.numopts = 1; 196 | edns.opt.opts = &opt; 197 | 198 | query.arcount = 1; 199 | query.additional = &edns; 200 | } 201 | 202 | reqsize = sizeof(request); 203 | rc = dns_encode(request,&reqsize,&query); 204 | if (rc != RCODE_OKAY) 205 | { 206 | fprintf(stderr,"dns_encode() = (%d) %s\n",rc,dns_rcode_text(rc)); 207 | return EXIT_FAILURE; 208 | } 209 | 210 | if (fdump) 211 | { 212 | printf("OUTGOING:\n\n"); 213 | dns_dump_memory(stdout,request,reqsize,0); 214 | } 215 | 216 | /*----------------------------------------------------------------------- 217 | ; Sending a DNS query. This uses the simple interface provided and is 218 | ; not good for much *except* as an example. If you have any complex 219 | ; requirements, do not look to this code. 220 | ;-----------------------------------------------------------------------*/ 221 | 222 | sockaddr_all server; 223 | dns_packet_t reply[DNS_BUFFER_UDP]; 224 | size_t replysize; 225 | 226 | rc = net_server(&server,serverhost); 227 | if (rc != 0) 228 | { 229 | fprintf(stderr,"net_server() = %s",strerror(rc)); 230 | return EXIT_FAILURE; 231 | } 232 | 233 | replysize = sizeof(reply); 234 | rc = net_request(&server,reply,&replysize,request,reqsize); 235 | if (rc != 0) 236 | { 237 | fprintf(stderr,"net_request() = %s\n",strerror(rc)); 238 | return EXIT_FAILURE; 239 | } 240 | 241 | if (fdump) 242 | { 243 | printf("\nINCOMING:\n\n"); 244 | dns_dump_memory(stdout,reply,replysize,0); 245 | } 246 | 247 | /*---------------------------------------------------------------------- 248 | ; Decode a DNS packet into something we can use. dns_decoded_t is a type 249 | ; to ensure proper alignment for stack based results---this must be big 250 | ; enough to handle not only the dns_query_t but additional information as 251 | ; well. The 4K size so far seems good enough for decoding UDP packets, 252 | ; although I'm using the 8K size just in case. 253 | ;-----------------------------------------------------------------------*/ 254 | 255 | dns_decoded_t bufresult[DNS_DECODEBUF_8K]; 256 | size_t bufsize; 257 | 258 | bufsize = sizeof(bufresult); 259 | rc = dns_decode(bufresult,&bufsize,reply,replysize); 260 | if (rc != RCODE_OKAY) 261 | { 262 | fprintf(stderr,"dns_decode() = (%d) %s\n",rc,dns_rcode_text(rc)); 263 | return EXIT_FAILURE; 264 | } 265 | 266 | if (fdump) 267 | printf("\nBytes used: %lu\n\n",(unsigned long)bufsize); 268 | 269 | /*---------------------------------------- 270 | ; see the code in output.c 271 | ;-----------------------------------------*/ 272 | 273 | dns_print_result((dns_query_t *)bufresult); 274 | return EXIT_SUCCESS; 275 | } 276 | 277 | /*********************************************************************/ 278 | 279 | static void usage(const char *prog) 280 | { 281 | assert(prog != NULL); 282 | 283 | fprintf( 284 | stderr, 285 | "usage: %s [-h] [-d] [-e] [-s server] host [type]\n" 286 | "\t-h\t\tusage text (this text)\n" 287 | "\t-d\t\tdump raw DNS queries\n" 288 | "\t-e\t\tInclude EDNS0 RR with query\n" 289 | "\t-s server\tIP address of server\n" 290 | "\n" 291 | "\ttype\t\tRR DNS type\n", 292 | prog 293 | ); 294 | } 295 | 296 | /**********************************************************************/ 297 | -------------------------------------------------------------------------------- /src/luadns.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * Copyright 2010 by Sean Conner. All Rights Reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or (at your 8 | * option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, see . 17 | * 18 | **************************************************************************/ 19 | 20 | /********************************************************************** 21 | * 22 | * Implements Lua bindings for my DNS library. This exports four functions 23 | * in the org.conman.dns object: 24 | * 25 | * encode(t) 26 | * 27 | * Accepts a table in the form: 28 | * 29 | * { 30 | * id = some_number, 31 | * query = true, -- making a query 32 | * rd = true, -- for recursive queries 33 | * opcode = 'query', 34 | * question = { 35 | * name = 'www.example.com', 36 | * type = 'loc', 37 | * class = 'in' 38 | * }, -- and optionally 39 | * additional = { 40 | * name = '.', 41 | * type = 'opt', 42 | * udp_payload = 1464, 43 | * version = 0, 44 | * fdo = false, 45 | * opts = { 46 | * { 47 | * type = 'nsid', -- or a number 48 | * data = "..." 49 | * } -- and more, if required 50 | * } 51 | * } 52 | * } 53 | * 54 | * And returns a binary string that is the wire format of the 55 | * query. This binary string can then be sent over a UDP or 56 | * TCP packet to a DNS server. 57 | * 58 | * This returns a binary string on success, nil,rcode on 59 | * failre. 60 | * 61 | * See lua/test.lua for an example of using this function. 62 | * 63 | * decode(bs) 64 | * 65 | * Decodes a binary string into a table (similar to the table 66 | * above) for easy use of the DNS response. 67 | * 68 | * This returns a table on success, or nil,rcode on failure. 69 | * 70 | * See lua/test.lua for an example of using this function. 71 | * 72 | * query(server,bs) 73 | * 74 | * Sends the encoded binary string to the given server. The 75 | * server variable is a string of the IP address (IPv4 or 76 | * IPv6)---hostnames will fail. 77 | * 78 | * This function is very stupid simple; it sends the request, 79 | * and if it doesn't see a reply in 15 seconds, it returns a 80 | * failure. No restransmission of the packet is done. This is 81 | * probably fine for simple applications but not for anything 82 | * heavy duty or rubust. 83 | * 84 | * This returns a binary string of the reponse, or nil,rcode on 85 | * failure. 86 | * 87 | * strerror(rcode) 88 | * 89 | * Returns a string representation of the server response, or 90 | * the return value from a failed query() call. This function 91 | * does not fail (if it does, there's more to worry about). 92 | * 93 | * 94 | * This code is written to C99. 95 | * 96 | ***************************************************************************/ 97 | 98 | #include 99 | #include 100 | #include 101 | #include 102 | 103 | #include 104 | #include 105 | 106 | #include "dns.h" 107 | #include "mappings.h" 108 | #include "netsimple.h" 109 | 110 | /********************************************************************/ 111 | 112 | #if LUA_VERSION_NUM == 501 113 | # define lua_rawlen(L,i) lua_objlen((L),(i)) 114 | static int lua_absindex(lua_State *L,int idx) 115 | { 116 | return (idx > 0) || (idx < LUA_REGISTRYINDEX) 117 | ? idx 118 | : lua_gettop(L) + idx + 1 119 | ; 120 | } 121 | #endif 122 | 123 | /********************************************************************/ 124 | 125 | static void to_question(lua_State *L,dns_question_t **pq,size_t *pqs,int idx) 126 | { 127 | assert(L != NULL); 128 | assert(pq != NULL); 129 | assert(pqs != NULL); 130 | assert(idx != 0); 131 | 132 | /*---------------------------------------------------------------------- 133 | ; while dns_encode() supports more than one question, most servers today 134 | ; (2021) *still* do not support more than one question, and most of the 135 | ; existing Lua code assumes one question. So let's keep with tradition 136 | ; for now. 137 | ;-----------------------------------------------------------------------*/ 138 | 139 | idx = lua_absindex(L,idx); 140 | *pqs = 1; 141 | *pq = lua_newuserdata(L,*pqs * sizeof(dns_question_t)); 142 | 143 | lua_getfield(L,idx,"name"); 144 | lua_getfield(L,idx,"type"); 145 | lua_getfield(L,idx,"class"); 146 | 147 | (*pq)[0].name = luaL_checkstring(L,-3); 148 | (*pq)[0].type = dns_type_value(luaL_optstring(L,-2,"A")); 149 | (*pq)[0].class = dns_class_value(luaL_optstring(L,-1,"IN")); 150 | lua_pop(L,3); 151 | } 152 | 153 | /********************************************************************/ 154 | 155 | static void to_dnsgpos_angle(lua_State *L,dnsgpos_angle *ang,int idx,bool lat) 156 | { 157 | lua_Number sec; 158 | 159 | idx = lua_absindex(L,idx); 160 | lua_getfield(L,idx,"deg"); 161 | lua_getfield(L,idx,"min"); 162 | lua_getfield(L,idx,"sec"); 163 | 164 | ang->deg = luaL_checkinteger(L,-3); 165 | ang->min = luaL_checkinteger(L,-2); 166 | ang->frac = modf(luaL_checknumber(L,-1),&sec) * 1000.0; 167 | ang->sec = sec; 168 | lua_pop(L,3); 169 | 170 | lua_getfield(L,idx,"hemisphere"); 171 | if (!lua_isnil(L,-1)) 172 | { 173 | char const *s = luaL_checkstring(L,-1); 174 | if (lat) 175 | ang->nw = toupper(*s) == 'N'; 176 | else 177 | ang->nw = toupper(*s) == 'W'; 178 | lua_pop(L,1); 179 | } 180 | else 181 | { 182 | lua_getfield(L,idx,"nw"); 183 | ang->nw = lua_toboolean(L,-1); 184 | lua_pop(L,2); 185 | } 186 | } 187 | 188 | /********************************************************************/ 189 | 190 | static void to_answers(lua_State *L,dns_answer_t **pa,size_t *pas,int idx) 191 | { 192 | int top; 193 | int tidx; 194 | 195 | assert(L != NULL); 196 | assert(pa != NULL); 197 | assert(pas != NULL); 198 | assert(idx != 0); 199 | 200 | idx = lua_absindex(L,idx); 201 | *pas = lua_rawlen(L,idx); 202 | *pa = lua_newuserdata(L,*pas * sizeof(dns_answer_t)); 203 | top = lua_gettop(L); 204 | 205 | for (size_t i = 0 ; i < *pas ; i++) 206 | { 207 | lua_pushinteger(L,i + 1); 208 | lua_gettable(L,idx); 209 | tidx = lua_absindex(L,-1); 210 | 211 | lua_getfield(L,tidx,"name"); 212 | lua_getfield(L,tidx,"type"); 213 | lua_getfield(L,tidx,"class"); 214 | lua_getfield(L,tidx,"ttl"); 215 | 216 | (*pa)[i].generic.name = luaL_checkstring(L,-4); 217 | (*pa)[i].generic.type = dns_type_value(luaL_checkstring(L,-3)); 218 | (*pa)[i].generic.class = dns_class_value(luaL_optstring(L,-2,"IN")); 219 | (*pa)[i].generic.ttl = luaL_checkinteger(L,-1); 220 | 221 | switch((*pa)[i].generic.type) 222 | { 223 | case RR_A: 224 | lua_getfield(L,tidx,"raw_address"); 225 | if (!lua_isnil(L,-1)) 226 | { 227 | size_t s; 228 | char const *a = luaL_checklstring(L,-1,&s); 229 | if (s != 4) luaL_error(L,"not an IP address in A record"); 230 | memcpy(&(*pa)[i].a.address,a,4); 231 | } 232 | else 233 | { 234 | lua_getfield(L,tidx,"address"); 235 | if (inet_pton(AF_INET,luaL_checkstring(L,-1),&(*pa)[i].a.address) != 0) 236 | luaL_error(L,"Not an IP address in A record"); 237 | } 238 | break; 239 | 240 | case RR_SOA: 241 | lua_getfield(L,tidx,"mname"); 242 | lua_getfield(L,tidx,"rname"); 243 | lua_getfield(L,tidx,"serial"); 244 | lua_getfield(L,tidx,"refresh"); 245 | lua_getfield(L,tidx,"retry"); 246 | lua_getfield(L,tidx,"expire"); 247 | lua_getfield(L,tidx,"minimum"); 248 | (*pa)[i].soa.mname = luaL_checkstring(L,-7); 249 | (*pa)[i].soa.rname = luaL_checkstring(L,-6); 250 | (*pa)[i].soa.serial = luaL_checkinteger(L,-5); 251 | (*pa)[i].soa.refresh = luaL_checkinteger(L,-4); 252 | (*pa)[i].soa.retry = luaL_checkinteger(L,-3); 253 | (*pa)[i].soa.expire = luaL_checkinteger(L,-2); 254 | (*pa)[i].soa.minimum = luaL_checkinteger(L,-1); 255 | break; 256 | 257 | case RR_NAPTR: 258 | lua_getfield(L,tidx,"order"); 259 | lua_getfield(L,tidx,"preference"); 260 | lua_getfield(L,tidx,"flags"); 261 | lua_getfield(L,tidx,"services"); 262 | lua_getfield(L,tidx,"regexp"); 263 | lua_getfield(L,tidx,"replacement"); 264 | (*pa)[i].naptr.order = luaL_checkinteger(L,-6); 265 | (*pa)[i].naptr.preference = luaL_checkinteger(L,-5); 266 | (*pa)[i].naptr.flags = luaL_checkstring(L,-4); 267 | (*pa)[i].naptr.services = luaL_checkstring(L,-3); 268 | (*pa)[i].naptr.regexp = luaL_checkstring(L,-2); 269 | (*pa)[i].naptr.replacement = luaL_checkstring(L,-1); 270 | break; 271 | 272 | case RR_AAAA: 273 | lua_getfield(L,tidx,"raw_address"); 274 | if (!lua_isnil(L,-1)) 275 | { 276 | size_t s; 277 | char const *a = luaL_checklstring(L,-1,&s); 278 | if (s != 16) luaL_error(L,"not an IPv6 address in AAAA record"); 279 | memcpy(&(*pa)[i].aaaa.address,a,16); 280 | } 281 | else 282 | { 283 | lua_getfield(L,tidx,"address"); 284 | if (inet_pton(AF_INET6,luaL_checkstring(L,-1),&(*pa)[i].aaaa.address) != 0) 285 | luaL_error(L,"not an IPv6 address in AAAA record"); 286 | } 287 | break; 288 | 289 | case RR_SRV: 290 | lua_getfield(L,tidx,"priority"); 291 | lua_getfield(L,tidx,"weight"); 292 | lua_getfield(L,tidx,"port"); 293 | lua_getfield(L,tidx,"target"); 294 | (*pa)[i].srv.priority = luaL_checkinteger(L,-4); 295 | (*pa)[i].srv.weight = luaL_checkinteger(L,-3); 296 | (*pa)[i].srv.port = luaL_checkinteger(L,-2); 297 | (*pa)[i].srv.target = luaL_checkstring(L,-1); 298 | break; 299 | 300 | case RR_WKS: 301 | lua_getfield(L,tidx,"raw_address"); 302 | if (!lua_isnil(L,-1)) 303 | { 304 | size_t s; 305 | char const *a = luaL_checklstring(L,-1,&s); 306 | if (s != 4) luaL_error(L,"not an IP address in A record"); 307 | memcpy(&(*pa)[i].wks.address,a,4); 308 | } 309 | else 310 | { 311 | lua_getfield(L,tidx,"address"); 312 | if (inet_pton(AF_INET,luaL_checkstring(L,-1),&(*pa)[i].wks.address) != 0) 313 | luaL_error(L,"Not an IP address in A record"); 314 | } 315 | 316 | lua_getfield(L,tidx,"protocol"); 317 | lua_getfield(L,tidx,"bits"); 318 | (*pa)[i].wks.protocol = luaL_checkinteger(L,-1); 319 | (*pa)[i].wks.bits = (uint8_t *)luaL_checklstring(L,-2,&(*pa)[i].wks.numbits); 320 | break; 321 | 322 | case RR_GPOS: 323 | lua_getfield(L,tidx,"longitude"); 324 | lua_getfield(L,tidx,"latitude"); 325 | lua_getfield(L,tidx,"altitude"); 326 | to_dnsgpos_angle(L,&(*pa)[i].gpos.longitude,-3,false); 327 | to_dnsgpos_angle(L,&(*pa)[i].gpos.latitude,-2,true); 328 | (*pa)[i].gpos.altitude = luaL_checknumber(L,-1); 329 | break; 330 | 331 | case RR_LOC: 332 | lua_getfield(L,tidx,"version"); 333 | lua_getfield(L,tidx,"size"); 334 | lua_getfield(L,tidx,"horiz_pre"); 335 | lua_getfield(L,tidx,"vert_pre"); 336 | lua_getfield(L,tidx,"latitude"); 337 | lua_getfield(L,tidx,"longitude"); 338 | lua_getfield(L,tidx,"altitude"); 339 | (*pa)[i].loc.version = luaL_optinteger(L,-7,0); 340 | (*pa)[i].loc.size = luaL_checkinteger(L,-6); 341 | (*pa)[i].loc.horiz_pre = luaL_checkinteger(L,-5); 342 | (*pa)[i].loc.vert_pre = luaL_checkinteger(L,-4); 343 | to_dnsgpos_angle(L,&(*pa)[i].loc.latitude,-3,true); 344 | to_dnsgpos_angle(L,&(*pa)[i].loc.longitude,-2,false); 345 | (*pa)[i].loc.altitude = luaL_checkinteger(L,-1); 346 | break; 347 | 348 | case RR_PX: 349 | lua_getfield(L,tidx,"map822"); 350 | lua_getfield(L,tidx,"mapx400"); 351 | (*pa)[i].px.map822 = luaL_checkstring(L,-2); 352 | (*pa)[i].px.mapx400 = luaL_checkstring(L,-1); 353 | break; 354 | 355 | case RR_RP: 356 | lua_getfield(L,tidx,"mbox"); 357 | lua_getfield(L,tidx,"domain"); 358 | (*pa)[i].rp.mbox = luaL_checkstring(L,-2); 359 | (*pa)[i].rp.domain = luaL_checkstring(L,-1); 360 | break; 361 | 362 | case RR_MINFO: 363 | lua_getfield(L,tidx,"rmailbx"); 364 | lua_getfield(L,tidx,"emailbx"); 365 | (*pa)[i].minfo.rmailbx = luaL_checkstring(L,-2); 366 | (*pa)[i].minfo.emailbx = luaL_checkstring(L,-1); 367 | break; 368 | 369 | case RR_AFSDB: 370 | lua_getfield(L,tidx,"subtype"); 371 | lua_getfield(L,tidx,"hostname"); 372 | (*pa)[i].afsdb.subtype = luaL_checkinteger(L,-2); 373 | (*pa)[i].afsdb.hostname = luaL_checkstring(L,-1); 374 | break; 375 | 376 | case RR_RT: 377 | lua_getfield(L,tidx,"preference"); 378 | lua_getfield(L,tidx,"host"); 379 | (*pa)[i].rt.preference = luaL_checkinteger(L,-2); 380 | (*pa)[i].rt.host = luaL_checkstring(L,-1); 381 | break; 382 | 383 | case RR_MX: 384 | lua_getfield(L,tidx,"preference"); 385 | lua_getfield(L,tidx,"exchange"); 386 | (*pa)[i].mx.preference = luaL_checkinteger(L,-2); 387 | (*pa)[i].mx.exchange = luaL_checkstring(L,-1); 388 | break; 389 | 390 | case RR_NSAP: 391 | lua_getfield(L,tidx,"length"); 392 | lua_getfield(L,tidx,"address"); 393 | (*pa)[i].nsap.length = luaL_checkstring(L,-2); 394 | (*pa)[i].nsap.nsapaddress = luaL_checkstring(L,-1); 395 | break; 396 | 397 | case RR_ISDN: 398 | lua_getfield(L,tidx,"address"); 399 | lua_getfield(L,tidx,"sa"); 400 | (*pa)[i].isdn.isdnaddress = luaL_checkstring(L,-2); 401 | (*pa)[i].isdn.sa = luaL_checkstring(L,-1); 402 | break; 403 | 404 | case RR_HINFO: 405 | lua_getfield(L,tidx,"cpu"); 406 | lua_getfield(L,tidx,"os"); 407 | (*pa)[i].hinfo.cpu = luaL_checkstring(L,-2); 408 | (*pa)[i].hinfo.os = luaL_checkstring(L,-1); 409 | break; 410 | 411 | case RR_X25: 412 | lua_getfield(L,tidx,"address"); 413 | (*pa)[i].x25.psdnaddress = luaL_checklstring(L,-1,&(*pa)[i].x25.size); 414 | break; 415 | 416 | case RR_SPF: 417 | lua_getfield(L,tidx,"text"); 418 | (*pa)[i].spf.text = luaL_checklstring(L,-1,&(*pa)[i].spf.len); 419 | break; 420 | 421 | case RR_TXT: 422 | lua_getfield(L,tidx,"text"); 423 | (*pa)[i].txt.text = luaL_checklstring(L,-1,&(*pa)[i].txt.len); 424 | break; 425 | 426 | case RR_NSAP_PTR: 427 | lua_getfield(L,tidx,"owner"); 428 | (*pa)[i].nsap_ptr.owner = luaL_checkstring(L,-1); 429 | break; 430 | 431 | case RR_MD: 432 | lua_getfield(L,tidx,"madname"); 433 | (*pa)[i].md.madname = luaL_checkstring(L,-1); 434 | break; 435 | 436 | case RR_MF: 437 | lua_getfield(L,tidx,"madname"); 438 | (*pa)[i].mf.madname = luaL_checkstring(L,-1); 439 | break; 440 | 441 | case RR_MB: 442 | lua_getfield(L,tidx,"madname"); 443 | (*pa)[i].mb.madname = luaL_checkstring(L,-1); 444 | break; 445 | 446 | case RR_MG: 447 | lua_getfield(L,tidx,"mgmname"); 448 | (*pa)[i].mg.mgmname = luaL_checkstring(L,-1); 449 | break; 450 | 451 | case RR_MR: 452 | lua_getfield(L,tidx,"newname"); 453 | (*pa)[i].mr.newname = luaL_checkstring(L,-1); 454 | break; 455 | 456 | case RR_NS: 457 | lua_getfield(L,tidx,"nsdname"); 458 | (*pa)[i].ns.nsdname = luaL_checkstring(L,-1); 459 | break; 460 | 461 | case RR_PTR: 462 | lua_getfield(L,tidx,"ptr"); 463 | (*pa)[i].ptr.ptr = luaL_checkstring(L,-1); 464 | break; 465 | 466 | case RR_CNAME: 467 | lua_getfield(L,tidx,"cname"); 468 | (*pa)[i].cname.cname = luaL_checkstring(L,-1); 469 | break; 470 | 471 | case RR_NULL: 472 | lua_getfield(L,tidx,"data"); 473 | (*pa)[i].null.data = (uint8_t *)luaL_checklstring(L,-1,&(*pa)[i].null.size); 474 | break; 475 | 476 | case RR_OPT: 477 | lua_getfield(L,tidx,"udp_payload"); 478 | lua_getfield(L,tidx,"version"); 479 | lua_getfield(L,tidx,"fdo"); 480 | lua_getfield(L,tidx,"fug"); 481 | lua_getfield(L,tidx,"z"); 482 | lua_getfield(L,tidx,"opts"); 483 | 484 | (*pa)[i].opt.udp_payload = luaL_checkinteger(L,-6); 485 | (*pa)[i].opt.version = luaL_checkinteger(L,-5); 486 | (*pa)[i].opt.fdo = lua_toboolean(L,-4); 487 | (*pa)[i].opt.fug = luaL_optinteger(L,-3,0); 488 | (*pa)[i].opt.z = luaL_optinteger(L,-2,0); 489 | (*pa)[i].opt.numopts = lua_rawlen(L,-1); 490 | (*pa)[i].opt.opts = lua_newuserdata(L,(*pa)[i].opt.numopts * sizeof(edns0_opt_t)); 491 | 492 | for (size_t j = 0 ; j < (*pa)[i].opt.numopts ; j++) 493 | { 494 | lua_pushinteger(L,j + 1); 495 | lua_gettable(L,-3); 496 | lua_getfield(L,-1,"data"); 497 | lua_getfield(L,-2,"code"); 498 | 499 | (*pa)[i].opt.opts[j].data = (uint8_t *)luaL_checklstring(L,-2,&(*pa)[i].opt.opts[j].len); 500 | if (lua_isnumber(L,-1)) 501 | (*pa)[i].opt.opts[j].code = lua_tointeger(L,-1); 502 | else if (lua_isstring(L,-1)) 503 | { 504 | if (strcmp("NSID",lua_tostring(L,-1)) == 0) 505 | (*pa)[i].opt.opts[j].code = EDNS0RR_NSID; 506 | else if (strcmp("nsid",lua_tostring(L,-1)) == 0) 507 | (*pa)[i].opt.opts[j].code = EDNS0RR_NSID; 508 | else 509 | luaL_error(L,"OPT RR code '%s' not supported",lua_tostring(L,-1)); 510 | } 511 | lua_pop(L,2); 512 | } 513 | 514 | break; 515 | 516 | default: break; 517 | } 518 | 519 | lua_settop(L,top); 520 | } 521 | } 522 | 523 | /********************************************************************/ 524 | 525 | static int dnslua_encode(lua_State *L) 526 | { 527 | dns_query_t query; 528 | dns_packet_t buffer[DNS_BUFFER_UDP_MAX]; 529 | size_t len; 530 | dns_rcode_t rc; 531 | 532 | luaL_checktype(L,1,LUA_TTABLE); 533 | lua_settop(L,1); 534 | 535 | lua_getfield(L,1,"id"); 536 | lua_getfield(L,1,"query"); 537 | lua_getfield(L,1,"opcode"); 538 | lua_getfield(L,1,"aa"); 539 | lua_getfield(L,1,"tc"); 540 | lua_getfield(L,1,"rd"); 541 | lua_getfield(L,1,"ra"); 542 | lua_getfield(L,1,"z"); 543 | lua_getfield(L,1,"ad"); 544 | lua_getfield(L,1,"cd"); 545 | lua_getfield(L,1,"rcode"); 546 | 547 | query.id = luaL_checkinteger(L,-11); 548 | query.query = lua_toboolean(L,-10); 549 | query.opcode = dns_op_value(luaL_optstring(L,-9,"QUERY")); 550 | query.aa = lua_toboolean(L,-8); 551 | query.tc = lua_toboolean(L,-7); 552 | query.rd = lua_toboolean(L,-6); 553 | query.ra = lua_toboolean(L,-5); 554 | query.z = lua_toboolean(L,-4); 555 | query.ad = lua_toboolean(L,-3); 556 | query.cd = lua_toboolean(L,-2); 557 | query.rcode = luaL_optinteger(L,-1,RCODE_OKAY); 558 | lua_pop(L,11); 559 | 560 | lua_getfield(L,1,"question"); 561 | to_question(L,&query.questions,&query.qdcount,-1); 562 | lua_getfield(L,1,"answers"); 563 | to_answers(L,&query.answers,&query.ancount,-1); 564 | lua_getfield(L,1,"nameservers"); 565 | to_answers(L,&query.nameservers,&query.nscount,-1); 566 | lua_getfield(L,1,"additional"); 567 | to_answers(L,&query.additional,&query.arcount,-1); 568 | 569 | len = sizeof(buffer); 570 | rc = dns_encode(buffer,&len,&query); 571 | 572 | if (rc != RCODE_OKAY) 573 | { 574 | lua_pushnil(L); 575 | lua_pushinteger(L,rc); 576 | return 2; 577 | } 578 | 579 | lua_pushlstring(L,(char *)buffer,len); 580 | lua_pushinteger(L,0); 581 | return 2; 582 | } 583 | 584 | /********************************************************************/ 585 | 586 | static void push_dnsgpos_angle(lua_State *L,dnsgpos_angle *pa,bool lat) 587 | { 588 | lua_createtable(L,0,4); 589 | lua_pushinteger(L,pa->deg); 590 | lua_setfield(L,-2,"deg"); 591 | lua_pushinteger(L,pa->min); 592 | lua_setfield(L,-2,"min"); 593 | lua_pushnumber(L,(double)pa->sec + ((double)pa->frac / 1000.0)); 594 | lua_setfield(L,-2,"sec"); 595 | lua_pushboolean(L,pa->nw); 596 | lua_setfield(L,-2,"nw"); 597 | if (lat) 598 | lua_pushlstring(L,(pa->nw) ? "N" : "S" , 1); 599 | else 600 | lua_pushlstring(L,(pa->nw) ? "W" : "E" , 1); 601 | lua_setfield(L,-2,"hemisphere"); 602 | } 603 | 604 | /********************************************************************/ 605 | 606 | static void decode_answer( 607 | lua_State *L, 608 | int tab, 609 | const char *name, 610 | dns_answer_t *pans, 611 | size_t cnt 612 | ) 613 | { 614 | char ipaddr[INET6_ADDRSTRLEN]; 615 | 616 | lua_createtable(L,cnt,0); 617 | 618 | for (size_t i = 0 ; i < cnt ; i++) 619 | { 620 | lua_pushinteger(L,i + 1); 621 | lua_createtable(L,0,0); 622 | 623 | lua_pushstring(L,pans[i].generic.name); 624 | lua_setfield(L,-2,"name"); 625 | lua_pushinteger(L,pans[i].generic.ttl); 626 | lua_setfield(L,-2,"ttl"); 627 | lua_pushstring(L,dns_class_text(pans[i].generic.class)); 628 | lua_setfield(L,-2,"class"); 629 | lua_pushstring(L,dns_type_text(pans[i].generic.type)); 630 | lua_setfield(L,-2,"type"); 631 | 632 | switch(pans[i].generic.type) 633 | { 634 | case RR_A: 635 | inet_ntop(AF_INET,&pans[i].a.address,ipaddr,sizeof(ipaddr)); 636 | lua_pushstring(L,ipaddr); 637 | lua_setfield(L,-2,"address"); 638 | lua_pushlstring(L,(char *)&pans[i].a.address,4); 639 | lua_setfield(L,-2,"raw_address"); 640 | break; 641 | 642 | case RR_SOA: 643 | lua_pushstring(L,pans[i].soa.mname); 644 | lua_setfield(L,-2,"mname"); 645 | lua_pushstring(L,pans[i].soa.rname); 646 | lua_setfield(L,-2,"rname"); 647 | lua_pushnumber(L,pans[i].soa.serial); 648 | lua_setfield(L,-2,"serial"); 649 | lua_pushnumber(L,pans[i].soa.refresh); 650 | lua_setfield(L,-2,"refresh"); 651 | lua_pushnumber(L,pans[i].soa.retry); 652 | lua_setfield(L,-2,"retry"); 653 | lua_pushnumber(L,pans[i].soa.expire); 654 | lua_setfield(L,-2,"expire"); 655 | lua_pushnumber(L,pans[i].soa.minimum); 656 | lua_setfield(L,-2,"minimum"); 657 | break; 658 | 659 | case RR_NAPTR: 660 | lua_pushinteger(L,pans[i].naptr.order); 661 | lua_setfield(L,-2,"order"); 662 | lua_pushinteger(L,pans[i].naptr.preference); 663 | lua_setfield(L,-2,"preference"); 664 | lua_pushstring(L,pans[i].naptr.flags); 665 | lua_setfield(L,-2,"flags"); 666 | lua_pushstring(L,pans[i].naptr.services); 667 | lua_setfield(L,-2,"services"); 668 | lua_pushstring(L,pans[i].naptr.regexp); 669 | lua_setfield(L,-2,"regexp"); 670 | lua_pushstring(L,pans[i].naptr.replacement); 671 | lua_setfield(L,-2,"replacement"); 672 | break; 673 | 674 | case RR_AAAA: 675 | inet_ntop(AF_INET6,&pans[i].aaaa.address,ipaddr,sizeof(ipaddr)); 676 | lua_pushstring(L,ipaddr); 677 | lua_setfield(L,-2,"address"); 678 | lua_pushlstring(L,(char *)&pans[i].aaaa.address,16); 679 | lua_setfield(L,-2,"raw_address"); 680 | break; 681 | 682 | case RR_SRV: 683 | lua_pushinteger(L,pans[i].srv.priority); 684 | lua_setfield(L,-2,"priority"); 685 | lua_pushinteger(L,pans[i].srv.weight); 686 | lua_setfield(L,-2,"weight"); 687 | lua_pushinteger(L,pans[i].srv.port); 688 | lua_setfield(L,-2,"port"); 689 | lua_pushstring(L,pans[i].srv.target); 690 | lua_setfield(L,-2,"target"); 691 | break; 692 | 693 | case RR_WKS: 694 | inet_ntop(AF_INET,&pans[i].wks.address,ipaddr,sizeof(ipaddr)); 695 | lua_pushstring(L,ipaddr); 696 | lua_setfield(L,-2,"address"); 697 | lua_pushlstring(L,(char *)&pans[i].wks.address,4); 698 | lua_setfield(L,-2,"raw_address"); 699 | lua_pushinteger(L,pans[i].wks.protocol); 700 | lua_setfield(L,-2,"protocol"); 701 | lua_pushlstring(L,(char *)pans[i].wks.bits,pans[i].wks.numbits); 702 | lua_setfield(L,-2,"bits"); 703 | break; 704 | 705 | case RR_GPOS: 706 | push_dnsgpos_angle(L,&pans[i].gpos.latitude,true); 707 | lua_setfield(L,-2,"longitude"); 708 | push_dnsgpos_angle(L,&pans[i].gpos.longitude,false); 709 | lua_setfield(L,-2,"latitude"); 710 | lua_pushnumber(L,pans[i].gpos.altitude); 711 | lua_setfield(L,-2,"altitude"); 712 | break; 713 | 714 | case RR_LOC: 715 | lua_pushnumber(L,pans[i].loc.size); 716 | lua_setfield(L,-2,"size"); 717 | lua_pushnumber(L,pans[i].loc.horiz_pre); 718 | lua_setfield(L,-2,"horiz_pre"); 719 | lua_pushnumber(L,pans[i].loc.vert_pre); 720 | lua_setfield(L,-2,"vert_pre"); 721 | push_dnsgpos_angle(L,&pans[i].loc.latitude,true); 722 | lua_setfield(L,-2,"latitude"); 723 | push_dnsgpos_angle(L,&pans[i].loc.longitude,false); 724 | lua_setfield(L,-2,"longitude"); 725 | lua_pushnumber(L,pans[i].loc.altitude); 726 | lua_setfield(L,-2,"altitude"); 727 | break; 728 | 729 | case RR_PX: 730 | lua_pushstring(L,pans[i].px.map822); 731 | lua_setfield(L,-2,"map822"); 732 | lua_pushstring(L,pans[i].px.mapx400); 733 | lua_setfield(L,-2,"mapx400"); 734 | break; 735 | 736 | case RR_RP: 737 | lua_pushstring(L,pans[i].rp.mbox); 738 | lua_setfield(L,-2,"mbox"); 739 | lua_pushstring(L,pans[i].rp.domain); 740 | lua_setfield(L,-2,"domain"); 741 | break; 742 | 743 | case RR_MINFO: 744 | lua_pushstring(L,pans[i].minfo.rmailbx); 745 | lua_setfield(L,-2,"rmailbx"); 746 | lua_pushstring(L,pans[i].minfo.emailbx); 747 | lua_setfield(L,-2,"emailbx"); 748 | break; 749 | 750 | case RR_AFSDB: 751 | lua_pushinteger(L,pans[i].afsdb.subtype); 752 | lua_setfield(L,-2,"subtype"); 753 | lua_pushstring(L,pans[i].afsdb.hostname); 754 | lua_setfield(L,-2,"hostname"); 755 | break; 756 | 757 | case RR_RT: 758 | lua_pushinteger(L,pans[i].rt.preference); 759 | lua_setfield(L,-2,"preference"); 760 | lua_pushstring(L,pans[i].rt.host); 761 | lua_setfield(L,-2,"host"); 762 | break; 763 | 764 | case RR_MX: 765 | lua_pushinteger(L,pans[i].mx.preference); 766 | lua_setfield(L,-2,"preference"); 767 | lua_pushstring(L,pans[i].mx.exchange); 768 | lua_setfield(L,-2,"exchange"); 769 | break; 770 | 771 | case RR_NSAP: 772 | lua_pushstring(L,pans[i].nsap.length); 773 | lua_setfield(L,-2,"length"); 774 | lua_pushstring(L,pans[i].nsap.nsapaddress); 775 | lua_setfield(L,-2,"address"); 776 | break; 777 | 778 | case RR_ISDN: 779 | lua_pushstring(L,pans[i].isdn.isdnaddress); 780 | lua_setfield(L,-2,"address"); 781 | lua_pushstring(L,pans[i].isdn.sa); 782 | lua_setfield(L,-2,"sa"); 783 | break; 784 | 785 | case RR_HINFO: 786 | lua_pushstring(L,pans[i].hinfo.cpu); 787 | lua_setfield(L,-2,"cpu"); 788 | lua_pushstring(L,pans[i].hinfo.os); 789 | lua_setfield(L,-2,"os"); 790 | break; 791 | 792 | case RR_X25: 793 | lua_pushlstring(L,pans[i].x25.psdnaddress,pans[i].x25.size); 794 | lua_setfield(L,-2,"address"); 795 | break; 796 | 797 | case RR_SPF: 798 | lua_pushlstring(L,pans[i].spf.text,pans[i].spf.len); 799 | lua_setfield(L,-2,"text"); 800 | break; 801 | 802 | case RR_TXT: 803 | lua_pushlstring(L,pans[i].txt.text,pans[i].txt.len); 804 | lua_setfield(L,-2,"text"); 805 | break; 806 | 807 | case RR_NSAP_PTR: 808 | lua_pushstring(L,pans[i].nsap_ptr.owner); 809 | lua_setfield(L,-2,"owner"); 810 | break; 811 | 812 | case RR_MD: 813 | lua_pushstring(L,pans[i].md.madname); 814 | lua_setfield(L,-2,"madname"); 815 | break; 816 | 817 | case RR_MF: 818 | lua_pushstring(L,pans[i].mf.madname); 819 | lua_setfield(L,-2,"madname"); 820 | break; 821 | 822 | case RR_MB: 823 | lua_pushstring(L,pans[i].mb.madname); 824 | lua_setfield(L,-2,"madname"); 825 | break; 826 | 827 | case RR_MG: 828 | lua_pushstring(L,pans[i].mg.mgmname); 829 | lua_setfield(L,-2,"mgmname"); 830 | break; 831 | 832 | case RR_MR: 833 | lua_pushstring(L,pans[i].mr.newname); 834 | lua_setfield(L,-2,"newname"); 835 | break; 836 | 837 | case RR_NS: 838 | lua_pushstring(L,pans[i].ns.nsdname); 839 | lua_setfield(L,-2,"nsdname"); 840 | break; 841 | 842 | case RR_PTR: 843 | lua_pushstring(L,pans[i].ptr.ptr); 844 | lua_setfield(L,-2,"ptr"); 845 | break; 846 | 847 | case RR_CNAME: 848 | lua_pushstring(L,pans[i].cname.cname); 849 | lua_setfield(L,-2,"cname"); 850 | break; 851 | 852 | case RR_NULL: 853 | lua_pushlstring(L,(char *)pans[i].null.data,pans[i].null.size); 854 | lua_setfield(L,-2,"data"); 855 | break; 856 | 857 | case RR_OPT: 858 | lua_pushinteger(L,pans[i].opt.udp_payload); 859 | lua_setfield(L,-2,"udp_payload"); 860 | lua_pushinteger(L,pans[i].opt.version); 861 | lua_setfield(L,-2,"version"); 862 | lua_pushboolean(L,pans[i].opt.fdo); 863 | lua_setfield(L,-2,"fdo"); 864 | lua_pushinteger(L,pans[i].opt.fug); 865 | lua_setfield(L,-2,"fug"); 866 | lua_pushinteger(L,pans[i].opt.z); 867 | lua_setfield(L,-2,"z"); 868 | lua_createtable(L,pans[i].opt.numopts,0); 869 | for (size_t j = 0 ; j < pans[i].opt.numopts ; j++) 870 | { 871 | lua_pushinteger(L,j + 1); 872 | lua_createtable(L,0,2); 873 | lua_pushlstring(L,(char *)pans[i].opt.opts[j].data,pans[i].opt.opts[j].len); 874 | lua_setfield(L,-2,"data"); 875 | if (pans[i].opt.opts[j].code == EDNS0RR_NSID) 876 | lua_pushstring(L,"NSID"); 877 | else 878 | lua_pushinteger(L,pans[i].opt.opts[j].code); 879 | lua_setfield(L,-2,"code"); 880 | lua_settable(L,-3); 881 | } 882 | lua_setfield(L,-2,"opts"); 883 | break; 884 | 885 | default: 886 | lua_pushlstring(L,(char *)pans[i].x.rawdata,pans[i].x.size); 887 | lua_setfield(L,-2,"rawdata"); 888 | break; 889 | } 890 | 891 | lua_settable(L,-3); 892 | } 893 | 894 | lua_setfield(L,tab,name); 895 | } 896 | 897 | /**********************************************************************/ 898 | 899 | static int dnslua_decode(lua_State *L) 900 | { 901 | dns_decoded_t bufresult[DNS_DECODEBUF_8K]; 902 | dns_packet_t data [DNS_DECODEBUF_4K]; 903 | const char *luadata; 904 | dns_query_t *result; 905 | size_t size; 906 | int tab; 907 | int rc; 908 | 909 | /*--------------------------------------------------------------------- 910 | ; We need to make sure our data is properly aligned. And hey, this is 911 | ; Lua---a scripting lanague. We can afford a bit of waste 8-) 912 | ;----------------------------------------------------------------------*/ 913 | 914 | luadata = luaL_checklstring(L,1,&size); 915 | if (size > sizeof(data)) size = sizeof(data); 916 | memcpy(data,luadata,size); 917 | 918 | rc = dns_decode(bufresult,&(size_t){sizeof(bufresult)},data,size); 919 | 920 | if (rc != RCODE_OKAY) 921 | { 922 | lua_pushnil(L); 923 | lua_pushinteger(L,rc); 924 | return 2; 925 | } 926 | 927 | result = (dns_query_t *)bufresult; 928 | 929 | lua_createtable(L,0,0); 930 | tab = lua_gettop(L); 931 | 932 | lua_pushinteger(L,result->id); 933 | lua_setfield(L,tab,"id"); 934 | lua_pushboolean(L,result->query); 935 | lua_setfield(L,tab,"query"); 936 | lua_pushstring(L,dns_op_text(result->opcode)); 937 | lua_setfield(L,tab,"opcode"); 938 | lua_pushboolean(L,result->aa); 939 | lua_setfield(L,tab,"aa"); 940 | lua_pushboolean(L,result->tc); 941 | lua_setfield(L,tab,"tc"); 942 | lua_pushboolean(L,result->rd); 943 | lua_setfield(L,tab,"rd"); 944 | lua_pushboolean(L,result->ra); 945 | lua_setfield(L,tab,"ra"); 946 | lua_pushboolean(L,result->z); 947 | lua_setfield(L,tab,"z"); 948 | lua_pushboolean(L,result->ad); 949 | lua_setfield(L,tab,"ad"); 950 | lua_pushboolean(L,result->cd); 951 | lua_setfield(L,tab,"cd"); 952 | lua_pushinteger(L,result->rcode); 953 | lua_setfield(L,tab,"rcode"); 954 | 955 | if (result->qdcount) 956 | { 957 | lua_createtable(L,0,3); 958 | lua_pushstring(L,result->questions[0].name); 959 | lua_setfield(L,-2,"name"); 960 | lua_pushstring(L,dns_class_text(result->questions[0].class)); 961 | lua_setfield(L,-2,"class"); 962 | lua_pushstring(L,dns_type_text(result->questions[0].type)); 963 | lua_setfield(L,-2,"type"); 964 | lua_setfield(L,tab,"question"); 965 | } 966 | 967 | decode_answer(L,tab,"answers" , result->answers , result->ancount); 968 | decode_answer(L,tab,"nameservers" , result->nameservers, result->nscount); 969 | decode_answer(L,tab,"additional" , result->additional , result->arcount); 970 | 971 | assert(tab == lua_gettop(L)); 972 | lua_pushinteger(L,0); 973 | return 2; 974 | } 975 | 976 | /*********************************************************************/ 977 | 978 | static int dnslua_strerror(lua_State *L) 979 | { 980 | if (lua_isnumber(L,1)) 981 | lua_pushstring(L,dns_rcode_text(lua_tointeger(L,1))); 982 | else 983 | lua_pushliteral(L,"uninown error"); 984 | return 1; 985 | } 986 | 987 | /*********************************************************************/ 988 | 989 | static int dnslua_query(lua_State *L) 990 | { 991 | sockaddr_all srvaddr; 992 | const char *server; 993 | const char *luaquery; 994 | size_t querysize; 995 | dns_packet_t query[DNS_BUFFER_UDP_MAX]; 996 | dns_packet_t reply[DNS_DECODEBUF_4K]; 997 | size_t replysize; 998 | int rc; 999 | 1000 | server = luaL_checkstring(L,1); 1001 | luaquery = luaL_checklstring(L,2,&querysize); 1002 | 1003 | if (net_server(&srvaddr,server) < 0) 1004 | luaL_error(L,"%s is not an IPv4/IPv6 address",server); 1005 | 1006 | if (querysize > MAX_DNS_QUERY_SIZE) querysize = MAX_DNS_QUERY_SIZE; 1007 | memcpy(query,luaquery,querysize); 1008 | replysize = sizeof(reply); 1009 | rc = net_request(&srvaddr,reply,&replysize,query,querysize); 1010 | 1011 | if (rc != 0) 1012 | { 1013 | lua_pushnil(L); 1014 | lua_pushinteger(L,rc); 1015 | return 2; 1016 | } 1017 | 1018 | lua_pushlstring(L,(char *)reply,replysize); 1019 | lua_pushinteger(L,0); 1020 | return 2; 1021 | } 1022 | 1023 | /**********************************************************************/ 1024 | 1025 | static const struct luaL_Reg reg_dns[] = 1026 | { 1027 | { "encode" , dnslua_encode } , 1028 | { "decode" , dnslua_decode } , 1029 | { "strerror" , dnslua_strerror } , 1030 | { "query" , dnslua_query } , 1031 | { NULL , NULL } 1032 | }; 1033 | 1034 | int luaopen_org_conman_dns(lua_State *L) 1035 | { 1036 | #if LUA_VERSION_NUM == 501 1037 | luaL_register(L,"org.conman.dns",reg_dns); 1038 | #else 1039 | luaL_newlib(L,reg_dns); 1040 | #endif 1041 | 1042 | lua_createtable(L,0,0); 1043 | for (size_t i = 0 ; c_dns_rcode_enum[i].text != NULL ; i++) 1044 | { 1045 | lua_pushinteger(L,c_dns_rcode_enum[i].value); 1046 | lua_setfield(L,-2,c_dns_rcode_enum[i].text); 1047 | } 1048 | lua_setfield(L,-2,"errno"); 1049 | 1050 | lua_pushliteral(L,VERSION); 1051 | lua_setfield(L,-2,"_VERSION"); 1052 | 1053 | return 1; 1054 | } 1055 | 1056 | /**********************************************************************/ 1057 | -------------------------------------------------------------------------------- /src/mappings.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * Copyright 2010 by Sean Conner. All Rights Reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or (at your 8 | * option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, see . 17 | * 18 | **************************************************************************/ 19 | 20 | /*********************************************************************** 21 | * 22 | * Implementation of mapping values to strings, or strings to values. 23 | * 24 | * This code is written to C99. 25 | * 26 | ************************************************************************/ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "dns.h" 34 | #include "mappings.h" 35 | 36 | /******************************************************************* 37 | * 38 | * The following structure is used to map strings to values. The arrays 39 | * defined by this structure *MUST* be sorted by the strings in ascending 40 | * order. 41 | * 42 | *********************************************************************/ 43 | 44 | struct string_int_map 45 | { 46 | char const *const text; 47 | int const value; 48 | }; 49 | 50 | /************************************************************************/ 51 | 52 | static struct int_string_map const cm_dns_rcode[] = 53 | { 54 | { RCODE_OKAY , "No error" } , 55 | { RCODE_FORMAT_ERROR , "Format error" } , 56 | { RCODE_SERVER_FAILURE , "Server failure" } , 57 | { RCODE_NAME_ERROR , "Non-existant domain" } , 58 | { RCODE_NOT_IMPLEMENTED , "Not implemented" } , 59 | { RCODE_REFUSED , "Query refused" } , 60 | { RCODE_YXDOMAIN , "Name exists when it should not" } , 61 | { RCODE_YXRRSET , "RRset exists when it should not" } , 62 | { RCODE_NXRRSET , "RRset does not exist" } , 63 | { RCODE_NOTAUTH , "Server not authoritative" } , 64 | { RCODE_NOTZONE , "Zone not in zone section" } , 65 | { RCODE_BADVERS , "Bad OPT version/TSIG failed" } , 66 | { RCODE_BADKEY , "Key not recognized" } , 67 | { RCODE_BADTIME , "Signature out of time window" } , 68 | { RCODE_BADMODE , "Bad TKEY mode" } , 69 | { RCODE_BADNAME , "Duplicate key name" } , 70 | { RCODE_BADALG , "Algorithm not supported" } , 71 | { RCODE_BADTRUC , "Bad truncation" } , 72 | { RCODE_BADCOOKIE , "Bad/missing server cookie" } , 73 | { RCODE_NO_MEMORY , "No memory" } , 74 | { RCODE_BAD_STRING , "Bad sring" } , 75 | }; 76 | 77 | #define RCODE_COUNT (sizeof(cm_dns_rcode) / sizeof(struct int_string_map)) 78 | 79 | struct int_string_map const c_dns_rcode_enum[] = 80 | { 81 | { RCODE_OKAY , "OKAY" } , 82 | { RCODE_FORMAT_ERROR , "FORMAT_ERROR" } , 83 | { RCODE_SERVER_FAILURE , "SERVER_FAILURE" } , 84 | { RCODE_NAME_ERROR , "NAME_ERROR" } , 85 | { RCODE_NOT_IMPLEMENTED , "NOT_IMPLEMENTED" } , 86 | { RCODE_REFUSED , "REFUSED" } , 87 | { RCODE_YXDOMAIN , "YXDOMAIN" } , 88 | { RCODE_YXRRSET , "YXRRSET" } , 89 | { RCODE_NXRRSET , "NXRRSET" } , 90 | { RCODE_NOTAUTH , "NOTAUTH" } , 91 | { RCODE_NOTZONE , "NOTZONE" } , 92 | { RCODE_BADVERS , "BADVERS" } , 93 | { RCODE_BADKEY , "BADKEY" } , 94 | { RCODE_BADTIME , "BADTIME" } , 95 | { RCODE_BADMODE , "BADMODE" } , 96 | { RCODE_BADNAME , "BADNAME" } , 97 | { RCODE_BADALG , "BADALG" } , 98 | { RCODE_BADTRUC , "BADTRUNC" } , 99 | { RCODE_BADCOOKIE , "BADCOOKIE" } , 100 | { RCODE_NO_MEMORY , "NO_MEMORY" } , 101 | { RCODE_BAD_STRING , "BAD_STRING" } , 102 | { 0 , NULL } , 103 | }; 104 | 105 | static struct string_int_map const cm_dns_rcode_is[] = 106 | { 107 | { "BADALG" , RCODE_BADALG } , 108 | { "BADCOOKIE" , RCODE_BADCOOKIE } , 109 | { "BADKEY" , RCODE_BADKEY } , 110 | { "BADMODE" , RCODE_BADMODE } , 111 | { "BADNAME" , RCODE_BADNAME } , 112 | { "BADTIME" , RCODE_BADTIME } , 113 | { "BADTRUNC" , RCODE_BADTRUC } , 114 | { "BADVERS" , RCODE_BADVERS } , 115 | { "BAD_STRING" , RCODE_BAD_STRING } , 116 | { "FORMAT_ERROR" , RCODE_FORMAT_ERROR } , 117 | { "NAME_ERROR" , RCODE_NAME_ERROR } , 118 | { "NOTAUTH" , RCODE_NOTAUTH } , 119 | { "NOTZONE" , RCODE_NOTZONE } , 120 | { "NOT_IMPLEMENTED" , RCODE_NOT_IMPLEMENTED } , 121 | { "NO_MEMORY" , RCODE_NO_MEMORY } , 122 | { "NXRRSET" , RCODE_NXRRSET } , 123 | { "OKAY" , RCODE_OKAY } , 124 | { "REFUSED" , RCODE_REFUSED } , 125 | { "SERVER_FAILURE" , RCODE_SERVER_FAILURE } , 126 | { "YXDOMAIN" , RCODE_YXDOMAIN } , 127 | { "YXRRSET" , RCODE_YXRRSET } , 128 | }; 129 | 130 | static struct int_string_map const cm_dns_type[] = 131 | { 132 | { RR_A , "A" } , 133 | { RR_NS , "NS" } , 134 | { RR_MD , "MD" } , 135 | { RR_MF , "MF" } , 136 | { RR_CNAME , "CNAME" } , 137 | { RR_SOA , "SOA" } , 138 | { RR_MB , "MB" } , 139 | { RR_MG , "MG" } , 140 | { RR_MR , "MR" } , 141 | { RR_NULL , "NULL" } , 142 | { RR_WKS , "WKS" } , 143 | { RR_PTR , "PTR" } , 144 | { RR_HINFO , "HINFO" } , 145 | { RR_MINFO , "MINFO" } , 146 | { RR_MX , "MX" } , 147 | { RR_TXT , "TXT" } , 148 | { RR_RP , "RP" } , 149 | { RR_AFSDB , "AFSDB" } , 150 | { RR_X25 , "X25" } , 151 | { RR_ISDN , "ISDN" } , 152 | { RR_RT , "RT" } , 153 | { RR_NSAP , "NSAP" } , 154 | { RR_NSAP_PTR , "NSAP-PTR" } , 155 | { RR_SIG , "SIG" } , 156 | { RR_KEY , "KEY" } , 157 | { RR_PX , "PX" } , 158 | { RR_GPOS , "GPOS" } , 159 | { RR_AAAA , "AAAA" } , 160 | { RR_LOC , "LOC" } , 161 | { RR_NXT , "NXT" } , 162 | { RR_EID , "EID" } , 163 | { RR_NIMLOC , "NIMLOC" } , 164 | { RR_SRV , "SRV" } , 165 | { RR_ATMA , "ATMA" } , 166 | { RR_NAPTR , "NAPTR" } , 167 | { RR_KX , "KX" } , 168 | { RR_CERT , "CERT" } , 169 | { RR_A6 , "A6" } , 170 | { RR_DNAME , "DNAME" } , 171 | { RR_SINK , "SINK" } , 172 | { RR_OPT , "OPT" } , 173 | { RR_APL , "APL" } , 174 | { RR_DS , "DS" } , 175 | { RR_SSHFP , "SSHFP" } , 176 | { RR_ISECKEY , "ISECKEY" } , 177 | { RR_RRSIG , "RRSIG" } , 178 | { RR_NSEC , "NSEC" } , 179 | { RR_DNSKEY , "DNSKEY" } , 180 | { RR_DHCID , "DHCID" } , 181 | { RR_NSEC3 , "NSEC3" } , 182 | { RR_NSEC3PARAM , "NSEC3PARAM" } , 183 | { RR_TLSA , "TLSA" } , 184 | { RR_SMIMEA , "SMIMEA" } , 185 | { RR_HIP , "HIP" } , 186 | { RR_NINFO , "NINFO" } , 187 | { RR_RKEY , "RKEY" } , 188 | { RR_TALINK , "TALINK" } , 189 | { RR_CDS , "CDS" } , 190 | { RR_CDNSKEY , "CDNSKEY" } , 191 | { RR_OPENPGPKEY , "OPENPGPKEY" } , 192 | { RR_CSYNC , "CSYNC" } , 193 | { RR_ZONEMD , "ZONEMD" } , 194 | { RR_HTTPS , "HTTPS" } , 195 | { RR_SPF , "SPF" } , 196 | { RR_UINFO , "UINFO" } , 197 | { RR_UID , "UID" } , 198 | { RR_GID , "GID" } , 199 | { RR_UNSPEC , "UNSPEC" } , 200 | { RR_NID , "NID" } , 201 | { RR_L32 , "L32" } , 202 | { RR_L64 , "L64" } , 203 | { RR_LP , "LP" } , 204 | { RR_EUI48 , "EUI48" } , 205 | { RR_EUI64 , "EUI64" } , 206 | { RR_TKEY , "TKEY" } , 207 | { RR_TSIG , "TSIG" } , 208 | { RR_IXFR , "IXFR" } , 209 | { RR_AXFR , "AXFR" } , 210 | { RR_MAILB , "MAILB" } , 211 | { RR_MAILA , "MAILA" } , 212 | { RR_ANY , "ANY" } , 213 | { RR_URI , "URI" } , 214 | { RR_CAA , "CAA" } , 215 | { RR_AVC , "AVC" } , 216 | { RR_DOA , "DOA" } , 217 | { RR_AMTRELAY , "AMTRELAY" } , 218 | { RR_TA , "TA" } , 219 | { RR_DLV , "DLV" } , 220 | { RR_PRIVATE , "PRIVATE" } , 221 | { RR_UNKNOWN , "UNKNOWN" } , 222 | }; 223 | 224 | #define TYPE_COUNT (sizeof(cm_dns_type) / sizeof(struct int_string_map)) 225 | 226 | static struct string_int_map const cm_dns_type_is[] = 227 | { 228 | { "A" , RR_A } , 229 | { "A6" , RR_A6 } , 230 | { "AAAA" , RR_AAAA } , 231 | { "AFSDB" , RR_AFSDB } , 232 | { "AMTRELAY" , RR_AMTRELAY } , 233 | { "ANY" , RR_ANY } , 234 | { "APL" , RR_APL } , 235 | { "ATMA" , RR_ATMA } , 236 | { "AVC" , RR_AVC } , 237 | { "AXFR" , RR_AXFR } , 238 | { "CAA" , RR_CAA } , 239 | { "CDNSKEY" , RR_CDNSKEY } , 240 | { "CDS" , RR_CDS } , 241 | { "CERT" , RR_CERT } , 242 | { "CNAME" , RR_CNAME } , 243 | { "CSYNC" , RR_CSYNC } , 244 | { "DHCID" , RR_DHCID } , 245 | { "DLV" , RR_DLV } , 246 | { "DNAME" , RR_DNAME } , 247 | { "DNSKEY" , RR_DNSKEY } , 248 | { "DOA" , RR_DOA } , 249 | { "DS" , RR_DS } , 250 | { "EID" , RR_EID } , 251 | { "EUI48" , RR_EUI48 } , 252 | { "EUI64" , RR_EUI64 } , 253 | { "GID" , RR_GID } , 254 | { "GPOS" , RR_GPOS } , 255 | { "HINFO" , RR_HINFO } , 256 | { "HIP" , RR_HIP } , 257 | { "HTTPS" , RR_HTTPS } , 258 | { "ISDN" , RR_ISDN } , 259 | { "ISECKEY" , RR_ISECKEY } , 260 | { "IXFR" , RR_IXFR } , 261 | { "KEY" , RR_KEY } , 262 | { "KX" , RR_KX } , 263 | { "L32" , RR_L32 } , 264 | { "L64" , RR_L64 } , 265 | { "LOC" , RR_LOC } , 266 | { "LP" , RR_LP } , 267 | { "MAILA" , RR_MAILA } , 268 | { "MAILB" , RR_MAILB } , 269 | { "MB" , RR_MB } , 270 | { "MD" , RR_MD } , 271 | { "MF" , RR_MF } , 272 | { "MG" , RR_MG } , 273 | { "MINFO" , RR_MINFO } , 274 | { "MR" , RR_MR } , 275 | { "MX" , RR_MX } , 276 | { "NAPTR" , RR_NAPTR } , 277 | { "NID" , RR_NID } , 278 | { "NIMLOC" , RR_NIMLOC } , 279 | { "NINFO" , RR_NINFO } , 280 | { "NS" , RR_NS } , 281 | { "NSAP" , RR_NSAP } , 282 | { "NSAP-PTR" , RR_NSAP_PTR } , 283 | { "NSEC" , RR_NSEC } , 284 | { "NSEC3" , RR_NSEC3 } , 285 | { "NSEC3PARAM" , RR_NSEC3PARAM } , 286 | { "NULL" , RR_NULL } , 287 | { "NXT" , RR_NXT } , 288 | { "OPENPGPKEY" , RR_OPENPGPKEY } , 289 | { "OPT" , RR_OPT } , 290 | { "PRIVATE" , RR_PRIVATE } , 291 | { "PTR" , RR_PTR } , 292 | { "PX" , RR_PX } , 293 | { "RKEY" , RR_RKEY } , 294 | { "RP" , RR_RP } , 295 | { "RRSIG" , RR_RRSIG } , 296 | { "RT" , RR_RT } , 297 | { "SIG" , RR_SIG } , 298 | { "SINK" , RR_SINK } , 299 | { "SMIMEA" , RR_SMIMEA } , 300 | { "SOA" , RR_SOA } , 301 | { "SPF" , RR_SPF } , 302 | { "SRV" , RR_SRV } , 303 | { "SSHFP" , RR_SSHFP } , 304 | { "TA" , RR_TA } , 305 | { "TALINK" , RR_TALINK } , 306 | { "TKEY" , RR_TKEY } , 307 | { "TLSA" , RR_TLSA } , 308 | { "TSIG" , RR_TSIG } , 309 | { "TXT" , RR_TXT } , 310 | { "UID" , RR_UID } , 311 | { "UINFO" , RR_UINFO } , 312 | { "UNKNOWN" , RR_UNKNOWN } , 313 | { "UNSPEC" , RR_UNSPEC } , 314 | { "URI" , RR_URI } , 315 | { "WKS" , RR_WKS } , 316 | { "X25" , RR_X25 } , 317 | { "ZONEMD" , RR_ZONEMD } , 318 | }; 319 | 320 | static struct int_string_map const cm_dns_class[] = 321 | { 322 | { CLASS_IN , "IN" } , 323 | { CLASS_CS , "CS" } , 324 | { CLASS_CH , "CH" } , 325 | { CLASS_HS , "HS" } , 326 | { CLASS_NONE , "NONE" } , 327 | { CLASS_ANY , "ANY" } , 328 | { CLASS_PRIVATE , "PRIVATE" } , 329 | { CLASS_UNKNOWN , "UNKNOWN" } , 330 | }; 331 | 332 | #define CLASS_COUNT (sizeof(cm_dns_class) / sizeof(struct int_string_map)) 333 | 334 | static struct string_int_map const cm_dns_class_is[] = 335 | { 336 | { "ANY" , CLASS_ANY } , 337 | { "CH" , CLASS_CH } , 338 | { "CS" , CLASS_CS } , 339 | { "HS" , CLASS_HS } , 340 | { "IN" , CLASS_IN } , 341 | { "NONE" , CLASS_NONE } , 342 | { "PRIVATE" , CLASS_PRIVATE } , 343 | { "UNKNOWN" , CLASS_UNKNOWN } , 344 | }; 345 | 346 | static struct int_string_map const cm_dns_op[] = 347 | { 348 | { OP_QUERY , "QUERY" } , 349 | { OP_UNKNOWN , "UKNOWN" } , 350 | { OP_STATUS , "STATUS" } , 351 | { OP_NOTIFY , "NOTIFY" } , 352 | { OP_UPDATE , "UPDATE" } , 353 | }; 354 | 355 | #define OP_COUNT (sizeof(cm_dns_op) / sizeof(struct int_string_map)) 356 | 357 | static struct string_int_map const cm_dns_op_is[] = 358 | { 359 | { "NOTIFY" , OP_NOTIFY } , 360 | { "QUERY" , OP_QUERY } , 361 | { "STATUS" , OP_STATUS } , 362 | { "UNKNOWN" , OP_UNKNOWN } , 363 | { "UPDATE" , OP_UPDATE } , 364 | }; 365 | 366 | /*************************************************************************/ 367 | 368 | static int intstr_cmp(void const *needle,void const *haystack) 369 | { 370 | struct int_string_map const *pism = haystack; 371 | int const *pi = needle; 372 | 373 | assert(needle != NULL); 374 | assert(haystack != NULL); 375 | 376 | return *pi - pism->value; 377 | } 378 | 379 | /*********************************************************************/ 380 | 381 | static int strint_cmp(void const *needle,void const *haystack) 382 | { 383 | struct string_int_map const *psim = haystack; 384 | char const *key = needle; 385 | 386 | assert(needle != NULL); 387 | assert(haystack != NULL); 388 | 389 | return strcmp(key,psim->text); 390 | } 391 | 392 | /**********************************************************************/ 393 | 394 | static char const *itosdef( 395 | int v, 396 | struct int_string_map const *pitab, 397 | size_t itabcnt, 398 | char const *def 399 | ) 400 | { 401 | struct int_string_map *pism; 402 | 403 | assert(v >= 0); 404 | assert(pitab != NULL); 405 | assert(itabcnt > 0); 406 | assert(def != NULL); 407 | 408 | pism = bsearch(&v,pitab,itabcnt,sizeof(struct int_string_map),intstr_cmp); 409 | if (pism) 410 | return pism->text; 411 | else 412 | return def; 413 | } 414 | 415 | /********************************************************************/ 416 | 417 | static int stoidef( 418 | char const *tag, 419 | struct string_int_map const *pstab, 420 | size_t stabcnt, 421 | int def 422 | ) 423 | { 424 | struct string_int_map *psim; 425 | size_t len = strlen(tag) + 1; 426 | char buffer[16]; 427 | size_t max = len > 15 ? 15 : len; 428 | 429 | memset(buffer,0,sizeof(buffer)); 430 | 431 | for (size_t i = 0 ; i < max ; i++) 432 | buffer[i] = toupper(tag[i]); 433 | 434 | psim = bsearch(buffer,pstab,stabcnt,sizeof(struct string_int_map),strint_cmp); 435 | if (psim) 436 | return psim->value; 437 | else 438 | return def; 439 | } 440 | 441 | /*******************************************************************/ 442 | 443 | char const *dns_rcode_enum(dns_rcode_t r) 444 | { 445 | return itosdef(r,c_dns_rcode_enum,RCODE_COUNT,"X-UNKN"); 446 | } 447 | 448 | /*******************************************************************/ 449 | 450 | char const *dns_rcode_text(dns_rcode_t r) 451 | { 452 | return itosdef(r,cm_dns_rcode,RCODE_COUNT,"Unknown error"); 453 | } 454 | 455 | /*********************************************************************/ 456 | 457 | char const *dns_type_text(dns_type_t t) 458 | { 459 | return itosdef(t,cm_dns_type,TYPE_COUNT,"X-UNKN"); 460 | } 461 | 462 | /**********************************************************************/ 463 | 464 | char const *dns_class_text(dns_class_t c) 465 | { 466 | return itosdef(c,cm_dns_class,CLASS_COUNT,"X-UNKN"); 467 | } 468 | 469 | /*******************************************************************/ 470 | 471 | char const *dns_op_text(dns_op_t o) 472 | { 473 | return itosdef(o,cm_dns_op,OP_COUNT,"X-UNKNOWN"); 474 | } 475 | 476 | /********************************************************************/ 477 | 478 | dns_rcode_t dns_rcode_value(char const *tag) 479 | { 480 | return stoidef(tag,cm_dns_rcode_is,RCODE_COUNT,RCODE_NOT_IMPLEMENTED); 481 | } 482 | 483 | /********************************************************************/ 484 | 485 | dns_type_t dns_type_value(char const *tag) 486 | { 487 | return stoidef(tag,cm_dns_type_is,TYPE_COUNT,RR_UNKNOWN); 488 | } 489 | 490 | /*********************************************************************/ 491 | 492 | dns_class_t dns_class_value(char const *tag) 493 | { 494 | return stoidef(tag,cm_dns_class_is,CLASS_COUNT,CLASS_UNKNOWN); 495 | } 496 | 497 | /**********************************************************************/ 498 | 499 | dns_op_t dns_op_value(char const *tag) 500 | { 501 | return stoidef(tag,cm_dns_op_is,OP_COUNT,OP_UNKNOWN); 502 | } 503 | 504 | /**********************************************************************/ 505 | -------------------------------------------------------------------------------- /src/mappings.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * Copyright 2010 by Sean Conner. All Rights Reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or (at your 8 | * option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, see . 17 | * 18 | **************************************************************************/ 19 | 20 | /************************************************************************** 21 | * 22 | * Useful routines to convert error codes, RR, Class and Opcode values into 23 | * strings, and strings into their equivilent RR, Class or Opcode values. 24 | * 25 | * This file assumes C99. You must include the following files before 26 | * including this one: 27 | * 28 | * #include "dns.h" 29 | * 30 | **************************************************************************/ 31 | 32 | #ifndef I_E2A4214D_2476_5EA3_92C1_9E450F8F349E 33 | #define I_E2A4214D_2476_5EA3_92C1_9E450F8F349E 34 | 35 | #ifdef __cplusplus 36 | extern "C" { 37 | #endif 38 | 39 | #ifndef __GNUC__ 40 | # define __attribute__(x) 41 | #endif 42 | 43 | struct int_string_map 44 | { 45 | int const value; 46 | char const *const text; 47 | }; 48 | 49 | extern struct int_string_map const c_dns_rcode_enum[]; 50 | 51 | extern char const *dns_rcode_enum (dns_rcode_t) __attribute__ ((pure,nothrow)); 52 | extern char const *dns_rcode_text (dns_rcode_t) __attribute__ ((pure,nothrow)); 53 | extern char const *dns_type_text (dns_type_t) __attribute__ ((pure,nothrow)); 54 | extern char const *dns_class_text (dns_class_t) __attribute__ ((pure,nothrow)); 55 | extern char const *dns_op_text (dns_op_t) __attribute__ ((pure,nothrow)); 56 | 57 | extern dns_rcode_t dns_rcode_value (char const *) __attribute__ ((pure,nothrow,nonnull)); 58 | extern dns_type_t dns_type_value (char const *) __attribute__ ((pure,nothrow,nonnull)); 59 | extern dns_class_t dns_class_value (char const *) __attribute__ ((pure,nothrow,nonnull)); 60 | extern dns_op_t dns_op_value (char const *) __attribute__ ((pure,nothrow,nonnull)); 61 | 62 | #ifdef __cplusplus 63 | } 64 | #endif 65 | #endif 66 | -------------------------------------------------------------------------------- /src/netsimple.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * Copyright 2010 by Sean Conner. All Rights Reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or (at your 8 | * option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, see . 17 | * 18 | **************************************************************************/ 19 | 20 | /********************************************************************* 21 | * 22 | * Implementation of the simple network interface for DNS queries. Two 23 | * functions are exported: 24 | * 25 | * net_server() 26 | * 27 | * decode the IP address (IPv4/IPv6) from a text representation 28 | * to a network format. 29 | * 30 | * net_request() 31 | * 32 | * Send a request to the given server and wait a reponse. This 33 | * function is stupid simple---it opens a socket, sends the 34 | * request via sendto(), waits for up to 15 seconds for a 35 | * reply. If no reply is seen in 15 seconds, close the socket 36 | * and return an error---otherwise, call recvfrom(), close the 37 | * socket and return the data. 38 | * 39 | * Like I said, stupid simple. It's enough for testing and 40 | * very simple programs. 41 | * 42 | * This code is written for C99. 43 | * 44 | **************************************************************************/ 45 | 46 | #include 47 | #include 48 | #include 49 | 50 | #include 51 | #include 52 | 53 | #include "dns.h" 54 | #include "netsimple.h" 55 | 56 | /************************************************************************/ 57 | 58 | int net_server( 59 | sockaddr_all *addr, 60 | char const *host 61 | ) 62 | { 63 | assert(addr != NULL); 64 | assert(host != NULL); 65 | 66 | memset(addr,0,sizeof(sockaddr_all)); 67 | 68 | if (inet_pton(AF_INET,host,&addr->sin.sin_addr.s_addr) < 0) 69 | { 70 | if (inet_pton(AF_INET6,host,&addr->sin6.sin6_addr.s6_addr) < 0) 71 | return errno; 72 | addr->sin6.sin6_family = AF_INET6; 73 | addr->sin6.sin6_port = htons(53); 74 | } 75 | else 76 | { 77 | addr->sin.sin_family = AF_INET; 78 | addr->sin.sin_port = htons(53); 79 | } 80 | 81 | return 0; 82 | } 83 | 84 | /************************************************************************/ 85 | 86 | int net_request( 87 | sockaddr_all *srvaddr, 88 | dns_packet_t *dest, 89 | size_t *dsize, 90 | dns_packet_t const *src, 91 | size_t ssize 92 | ) 93 | { 94 | struct pollfd polldat; 95 | socklen_t asize; 96 | ssize_t bytes; 97 | int sock; 98 | int rc; 99 | int err; 100 | 101 | switch(srvaddr->sa.sa_family) 102 | { 103 | case AF_INET: asize = sizeof(struct sockaddr_in); break; 104 | case AF_INET6: asize = sizeof(struct sockaddr_in6); break; 105 | default: assert(0); return EPROTOTYPE; 106 | } 107 | 108 | sock = socket(srvaddr->sa.sa_family,SOCK_DGRAM,0); 109 | if (sock < 0) 110 | return errno; 111 | 112 | bytes = sendto(sock,src,ssize,0,&srvaddr->sa,asize); 113 | if (bytes < 0) 114 | { 115 | err = errno; 116 | close(sock); 117 | return err; 118 | } 119 | 120 | polldat.fd = sock; 121 | polldat.events = POLLIN; 122 | 123 | rc = poll(&polldat,1,15000); 124 | if (rc < 0) 125 | { 126 | err = errno; 127 | close(sock); 128 | return err; 129 | } 130 | 131 | if (rc == 0) 132 | { 133 | close(sock); 134 | return ETIMEDOUT; 135 | } 136 | 137 | bytes = recvfrom(sock,dest,*dsize,0,NULL,NULL); 138 | if (bytes < 0) 139 | { 140 | int err = errno; 141 | close(sock); 142 | return err; 143 | } 144 | 145 | *dsize = bytes; 146 | close(sock); 147 | return 0; 148 | } 149 | 150 | /**************************************************************************/ 151 | -------------------------------------------------------------------------------- /src/netsimple.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * Copyright 2010 by Sean Conner. All Rights Reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or (at your 8 | * option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, see . 17 | * 18 | **************************************************************************/ 19 | 20 | /************************************************************************ 21 | * 22 | * Definitions for a simple network interface to send and receive DNS 23 | * queries. 24 | * 25 | * This only suffices for simple applications; for anything that does a lot 26 | * of DNS queries, you probably want to use something else. 27 | * 28 | * This file assumes C99. You must include the following files before 29 | * including this one: 30 | * 31 | * #include 32 | * #include 33 | * #include 34 | * 35 | * And if you want to decode the return values (beyond success/failure): 36 | * 37 | * #include 38 | * 39 | *************************************************************************/ 40 | 41 | #ifndef I_927898DC_135D_5C61_B435_21EC89A06D2D 42 | #define I_927898DC_135D_5C61_B435_21EC89A06D2D 43 | 44 | #ifdef __cplusplus 45 | extern "C" { 46 | #endif 47 | 48 | #ifndef __GNUC__ 49 | # define __attribute__(x) 50 | #endif 51 | 52 | typedef union sockaddr_all 53 | { 54 | struct sockaddr sa; 55 | struct sockaddr_in sin; 56 | struct sockaddr_in6 sin6; 57 | } sockaddr_all; 58 | 59 | extern int net_server (sockaddr_all *,char const *) __attribute__ ((nonnull)); 60 | extern int net_request(sockaddr_all *,dns_packet_t *,size_t *,dns_packet_t const *,size_t) __attribute__ ((nonnull(1,2,3,4))); 61 | 62 | #ifdef __cplusplus 63 | } 64 | #endif 65 | #endif 66 | -------------------------------------------------------------------------------- /src/output.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * Copyright 2010 by Sean Conner. All Rights Reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or (at your 8 | * option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, see . 17 | * 18 | **************************************************************************/ 19 | 20 | /********************************************************************** 21 | * 22 | * DNS record output functions used by sample application. 23 | * 24 | * It was factored out so it could be called from client applications. 25 | * 26 | ***************************************************************************/ 27 | 28 | #include 29 | #include 30 | 31 | #include "dns.h" 32 | #include "mappings.h" 33 | #include "output.h" 34 | 35 | /************************************************************************/ 36 | 37 | void dns_print_result(dns_query_t* presult) 38 | { 39 | /*------------------------------------------- 40 | ; Print the results out, ala dig 41 | ;-------------------------------------------*/ 42 | 43 | dns_print_header(presult); 44 | dns_print_question("QUESTIONS" ,presult->questions ,presult->qdcount); 45 | dns_print_answer ("ANSWERS" ,presult->answers ,presult->ancount); 46 | dns_print_answer ("NAMESERVERS" ,presult->nameservers ,presult->nscount); 47 | dns_print_answer ("ADDITIONAL" ,presult->additional ,presult->arcount); 48 | } 49 | 50 | /************************************************************************/ 51 | 52 | void dns_print_header(dns_query_t* presult) 53 | { 54 | printf( 55 | "; Questions = %lu\n" 56 | "; Answers = %lu\n" 57 | "; Name Servers = %lu\n" 58 | "; Additional Records = %lu\n" 59 | "; Authoritative Result = %s\n" 60 | "; Truncated Result = %s\n" 61 | "; Recursion Desired = %s\n" 62 | "; Recursion Available = %s\n" 63 | "; Authentic Data = %s\n" 64 | "; Checking disabled = %s\n" 65 | "; Result = %s\n", 66 | (unsigned long)presult->qdcount, 67 | (unsigned long)presult->ancount, 68 | (unsigned long)presult->nscount, 69 | (unsigned long)presult->arcount, 70 | presult->aa ? "true" : "false", 71 | presult->tc ? "true" : "false", 72 | presult->rd ? "true" : "false", 73 | presult->ra ? "true" : "false", 74 | presult->ad ? "true" : "false", 75 | presult->cd ? "true" : "false", 76 | dns_rcode_text(presult->rcode) 77 | ); 78 | } 79 | 80 | /************************************************************************/ 81 | 82 | void dns_print_question(char const *tag,dns_question_t *pquest,size_t cnt) 83 | { 84 | assert(tag != NULL); 85 | assert(pquest != NULL); 86 | 87 | printf("\n;;; %s\n\n",tag); 88 | for (size_t i = 0 ; i < cnt ; i++) 89 | { 90 | printf( 91 | ";%s %s %s\n", 92 | pquest[i].name, 93 | dns_class_text(pquest[i].class), 94 | dns_type_text (pquest[i].type) 95 | ); 96 | } 97 | } 98 | 99 | /***********************************************************************/ 100 | 101 | void dns_print_answer(char const *tag,dns_answer_t *pans,size_t cnt) 102 | { 103 | char ipaddr[INET6_ADDRSTRLEN]; 104 | 105 | assert(tag != NULL); 106 | assert(pans != NULL); 107 | 108 | printf("\n;;; %s\n\n",tag); 109 | 110 | for (size_t i = 0 ; i < cnt ; i++) 111 | { 112 | if (pans[i].generic.type != RR_OPT) 113 | { 114 | printf( 115 | "%-16s\t%5lu\t%s\t%s\t", 116 | pans[i].generic.name, 117 | (unsigned long)pans[i].generic.ttl, 118 | dns_class_text(pans[i].generic.class), 119 | dns_type_text (pans[i].generic.type) 120 | ); 121 | } 122 | else 123 | printf("; OPT RR"); 124 | 125 | switch(pans[i].generic.type) 126 | { 127 | case RR_NS: 128 | printf("%s",pans[i].ns.nsdname); 129 | break; 130 | case RR_A: 131 | inet_ntop(AF_INET,&pans[i].a.address,ipaddr,sizeof(ipaddr)); 132 | printf("%s",ipaddr); 133 | break; 134 | case RR_AAAA: 135 | inet_ntop(AF_INET6,&pans[i].aaaa.address,ipaddr,sizeof(ipaddr)); 136 | printf("%s",ipaddr); 137 | break; 138 | case RR_CNAME: 139 | printf("%s",pans[i].cname.cname); 140 | break; 141 | case RR_MX: 142 | printf("%5d %s",pans[i].mx.preference,pans[i].mx.exchange); 143 | break; 144 | case RR_PTR: 145 | printf("%s",pans[i].ptr.ptr); 146 | break; 147 | case RR_HINFO: 148 | printf("\"%s\" \"%s\"",pans[i].hinfo.cpu,pans[i].hinfo.os); 149 | break; 150 | case RR_MINFO: 151 | printf("(\n\t\t\"%s\"\n\t\t\"%s\" )",pans[i].minfo.rmailbx,pans[i].minfo.emailbx); 152 | break; 153 | case RR_SPF: 154 | case RR_TXT: 155 | if (pans[i].txt.len < 30) 156 | printf("\"%s\"",pans[i].txt.text); 157 | else 158 | { 159 | size_t len; 160 | int max; 161 | size_t off; 162 | 163 | printf("("); 164 | len = pans[i].txt.len; 165 | off = 0; 166 | 167 | while(len) 168 | { 169 | max = (len > 64) ? 64 : (int)len; 170 | printf("\n\t\"%*.*s\"",max,max,&pans[i].txt.text[off]); 171 | off += max; 172 | len -= max; 173 | } 174 | 175 | printf("\n\t\t)\n"); 176 | } 177 | break; 178 | case RR_SOA: 179 | printf( 180 | "%s %s (\n" 181 | "\t\t%10lu ; Serial\n" 182 | "\t\t%10lu ; Refresh\n" 183 | "\t\t%10lu ; Retry\n" 184 | "\t\t%10lu ; Expire\n" 185 | "\t\t%10lu ) ; Miminum\n", 186 | pans[i].soa.mname, 187 | pans[i].soa.rname, 188 | (unsigned long)pans[i].soa.serial, 189 | (unsigned long)pans[i].soa.refresh, 190 | (unsigned long)pans[i].soa.retry, 191 | (unsigned long)pans[i].soa.expire, 192 | (unsigned long)pans[i].soa.minimum 193 | ); 194 | break; 195 | case RR_NAPTR: 196 | printf( 197 | "%5d %5d (\n" 198 | "\t\t\"%s\"\n" 199 | "\t\t\"%s\"\n" 200 | "\t\t\"%s\"\n" 201 | "\t\t%s )\n", 202 | pans[i].naptr.order, 203 | pans[i].naptr.preference, 204 | pans[i].naptr.flags, 205 | pans[i].naptr.services, 206 | pans[i].naptr.regexp, 207 | pans[i].naptr.replacement 208 | ); 209 | break; 210 | case RR_LOC: 211 | printf( 212 | "(\n" 213 | "\t\t%3d %2d %2d %s ; Latitude\n" 214 | "\t\t%3d %2d %2d %s ; Longitude\n" 215 | "\t\t%11ld ; Altitude\n" 216 | "\t\t%11llu ; Size\n" 217 | "\t\t%11llu ; Horizontal Precision\n" 218 | "\t\t%11llu ; Vertical Precision\n" 219 | "\t\t)\n", 220 | pans[i].loc.latitude.deg, 221 | pans[i].loc.latitude.min, 222 | pans[i].loc.latitude.sec, 223 | pans[i].loc.latitude.nw ? "N" : "S", 224 | pans[i].loc.longitude.deg, 225 | pans[i].loc.longitude.min, 226 | pans[i].loc.longitude.sec, 227 | pans[i].loc.longitude.nw ? "W" : "E", 228 | pans[i].loc.altitude, 229 | pans[i].loc.size, 230 | pans[i].loc.horiz_pre, 231 | pans[i].loc.vert_pre 232 | ); 233 | break; 234 | case RR_SRV: 235 | printf( 236 | "%5d %5d %5d %s", 237 | pans[i].srv.priority, 238 | pans[i].srv.weight, 239 | pans[i].srv.port, 240 | pans[i].srv.target 241 | ); 242 | break; 243 | case RR_OPT: 244 | printf( 245 | "\n" 246 | ";\tpayload = %lu\n" 247 | ";\tDO = %s\n" 248 | ";\t#opts = %lu\n", 249 | (unsigned long)pans[i].opt.udp_payload, 250 | pans[i].opt.fdo ? "true" : "false", 251 | (unsigned long)pans[i].opt.numopts 252 | ); 253 | break; 254 | 255 | default: 256 | break; 257 | } 258 | printf("\n"); 259 | } 260 | } 261 | 262 | /**********************************************************************/ 263 | 264 | #define LINESIZE 16 265 | 266 | void dns_dump_memory(FILE *out,void const *data,size_t size,size_t offset) 267 | { 268 | unsigned char const *block = data; 269 | char ascii[LINESIZE + 1]; 270 | int skip; 271 | int j; 272 | 273 | assert(out != NULL); 274 | assert(block != NULL); 275 | assert(size > 0); 276 | 277 | while(size > 0) 278 | { 279 | fprintf(out,"%08lX: ",(unsigned long)offset); 280 | 281 | for (skip = offset % LINESIZE , j = 0 ; skip ; j++ , skip--) 282 | { 283 | fputs(" ",out); 284 | ascii[j] = ' '; 285 | } 286 | 287 | do 288 | { 289 | fprintf(out,"%02x ",*block); 290 | if (isprint(*block)) 291 | ascii[j] = *block; 292 | else 293 | ascii[j] = '.'; 294 | 295 | block++; 296 | offset++; 297 | j++; 298 | size--; 299 | } while((j < LINESIZE) && (size > 0)); 300 | 301 | ascii[j] = '\0'; 302 | 303 | if (j < LINESIZE) 304 | { 305 | int i; 306 | 307 | for (i = j ; i < LINESIZE ; i++) 308 | fputs(" ",out); 309 | } 310 | fprintf(out,"%s\n",ascii); 311 | } 312 | } 313 | 314 | /**********************************************************************/ 315 | -------------------------------------------------------------------------------- /src/output.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * Copyright 2010 by Sean Conner. All Rights Reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or (at your 8 | * option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this library; if not, see . 17 | * 18 | **************************************************************************/ 19 | 20 | /********************************************************************** 21 | * 22 | * Definitions for DNS record output functions used by sample application. 23 | * 24 | * It was factored out so it could be called from client applications. 25 | * 26 | ***************************************************************************/ 27 | 28 | #ifndef I_54636A09_9D2A_5B69_A900_EC8C8A59E060 29 | #define I_54636A09_9D2A_5B69_A900_EC8C8A59E060 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | #ifndef __GNUC__ 36 | # define __attribute__(x) 37 | #endif 38 | 39 | #include 40 | #include "dns.h" 41 | 42 | extern void dns_print_result (dns_query_t *); 43 | extern void dns_print_header (dns_query_t *); 44 | extern void dns_print_question (char const *,dns_question_t *,size_t); 45 | extern void dns_print_answer (char const *,dns_answer_t *,size_t); 46 | extern void dns_dump_memory (FILE *,void const *,size_t,size_t); 47 | 48 | #ifdef __cplusplus 49 | } 50 | #endif 51 | #endif 52 | --------------------------------------------------------------------------------