├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── src
├── Makefile
├── VERSION
├── asciilogo.h
├── dnsproxy.c
├── dnsproxy.h
├── domain_cache.c
├── embed
│ ├── LICENSE
│ ├── embed.h
│ ├── list.h
│ ├── rbtree.c
│ ├── rbtree.h
│ ├── xgetopt.c
│ └── xgetopt.h
└── transport_cache.c
└── utils
└── dnspd
/.gitignore:
--------------------------------------------------------------------------------
1 | .*
2 | *.vcxproj*
3 | *.sln
4 | *.suo
5 | *.sdf
6 | *.opensdf
7 | *.pdb
8 | /X64
9 | /Debug
10 | /Release
11 |
12 | *.o
13 | *.obj
14 | *.lib
15 | *.a
16 | *.dll
17 | *.so
18 | *.so.*
19 | *.dylib
20 | *.exe
21 | *.out
22 | *.app
23 |
24 | /GPATH
25 | /GRTAGS
26 | /GTAGS
27 | /TAGS
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # Top level Makefile, the real shit is at src/Makefile
2 |
3 | all:
4 | cd src && $(MAKE) $@
5 |
6 | clean:
7 | cd src && $(MAKE) $@
8 |
9 | install:
10 | cd src && $(MAKE) $@
11 |
12 | uninstall:
13 | cd src && $(MAKE) $@
14 |
15 | .PHONY: all clean install uninstall
16 |
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | dnsproxy
2 | ========
3 |
4 | A tiny caching DNS server
5 |
6 | ## Compiling & Installation
7 |
8 | ```bash
9 | $ git clone git://github.com/vietor/dnsproxy.git
10 | $ cd dnsproxy
11 | $ make && make install
12 | ```
13 |
14 | ## Simple tutorial
15 |
16 | ```bash
17 | $ dnsproxy -h
18 | Usage: dnsproxy [options]
19 | -d or --daemon
20 | (daemon mode)
21 | -p or --port=
22 | (local bind port, default 53)
23 | -R or --remote-addr=
24 | (remote server ip, default 8.8.8.8)
25 | -P or --remote-port=
26 | (remote server port, default 53)
27 | -T or --remote-tcp
28 | (connect remote server in tcp, default no)
29 | -f or --hosts-file=
30 | (user-defined hosts file)
31 | -h, --help (print help and exit)
32 | -v, --version (print version and exit)
33 | ```
34 |
35 | ## Hosts file example
36 |
37 | ```
38 | 127.0.0.1 example.com www.example.com
39 | 192.168.0.1 *.test.com
40 | 192.168.0.2 2*.test.com
41 | 192.168.0.3 *3.test.com
42 | ```
43 |
--------------------------------------------------------------------------------
/src/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile for dnsproxy
2 |
3 | uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
4 | version := $(shell sh -c 'cat VERSION')
5 |
6 | CC = gcc
7 | RM = rm -f
8 | CP = cp -f
9 |
10 | CFLAGS = -O2 -Wall -DVERSION=\"${version}\" -DNDEBUG
11 | LDFLAGS = -s
12 | PREFIX = /usr
13 |
14 | TARGET = dnsproxy
15 | INCLUDES = $(wildcard *.h embed/*.h)
16 | SOURCES = $(wildcard *.c embed/*.c)
17 | OBJS = $(patsubst %.c,%.o,$(SOURCES))
18 |
19 | ifneq (,$(findstring MINGW,$(uname_S)))
20 | CFLAGS +=
21 | LDFLAGS += -lws2_32 -lmswsock
22 | TARGET := $(TARGET).exe
23 | endif
24 |
25 | all: $(TARGET)
26 |
27 | %.o: %.c
28 | $(CC) $(CFLAGS) -c -o $@ $<
29 |
30 | $(OBJS): $(SOURCES) $(INCLUDES)
31 |
32 | $(TARGET): $(OBJS)
33 | $(CC) -o $(TARGET) $(OBJS) $(LDFLAGS)
34 |
35 | clean:
36 | $(RM) *.o embed/*.o *~ $(TARGET)
37 |
38 | install:
39 | $(CP) $(TARGET) $(PREFIX)/sbin
40 |
41 | uninstall:
42 | $(RM) $(PREFIX)/sbin/$(TARGET)
43 |
--------------------------------------------------------------------------------
/src/VERSION:
--------------------------------------------------------------------------------
1 | 1.1.1
2 |
--------------------------------------------------------------------------------
/src/asciilogo.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014, Vietor Liu
3 | *
4 | * This program is free software; you can redistribute it and/or
5 | * modify it under the terms of the GNU General Public License
6 | * as published by the Free Software Foundation; either version 2
7 | * of the License, or any later version. For full terms that can be
8 | * found in the LICENSE file.
9 | */
10 |
11 | char *ascii_logo =
12 | " _ \n"
13 | " | | licensed under GPLv2 \n"
14 | " __| |_ __ ___ _ __ _ __ _____ ___ _ \n"
15 | " / _` | '_ \\/ __| '_ \\| '__/ _ \\ \\/ / | | | \n"
16 | " | (_| | | | \\__ \\ |_) | | | (_) > <| |_| | \n"
17 | " \\__,_|_| |_|___/ .__/|_| \\___/_/\\_\\\\__, | \n"
18 | " | | __/ | \n"
19 | " |_| |___/ \n";
20 |
--------------------------------------------------------------------------------
/src/dnsproxy.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014, Vietor Liu
3 | *
4 | * This program is free software; you can redistribute it and/or
5 | * modify it under the terms of the GNU General Public License
6 | * as published by the Free Software Foundation; either version 2
7 | * of the License, or any later version. For full terms that can be
8 | * found in the LICENSE file.
9 | */
10 |
11 | #include "dnsproxy.h"
12 | #include "asciilogo.h"
13 |
14 | #ifndef VERSION
15 | #define VERSION "development"
16 | #endif
17 |
18 | #define PACKAGE_SIZE 8192
19 | #define CACHE_CLEAN_TIME (MIN_TTL / 2 + 1)
20 |
21 | #if defined(_MSC_VER)
22 | #pragma comment(lib,"ws2_32")
23 | #pragma comment(lib,"mswsock")
24 | #endif
25 |
26 | typedef struct {
27 | SOCKET sock;
28 | char buffer[PACKAGE_SIZE + sizeof(unsigned short)];
29 | } LOCAL_DNS;
30 |
31 | typedef struct {
32 | int tcp;
33 | SOCKET sock;
34 | struct sockaddr_in addr;
35 | unsigned int head;
36 | unsigned int rear;
37 | unsigned int capacity;
38 | char buffer[PACKAGE_SIZE * 3];
39 | } REMOTE_DNS;
40 |
41 | typedef struct {
42 | LOCAL_DNS local;
43 | REMOTE_DNS remote;
44 | } PROXY_ENGINE;
45 |
46 | static const int enable = 1;
47 | static int disable_cache = 0;
48 |
49 | static void process_query(PROXY_ENGINE *engine)
50 | {
51 | LOCAL_DNS *ldns;
52 | REMOTE_DNS *rdns;
53 | DNS_HDR *hdr, *rhdr;
54 | DNS_QDS *qds;
55 | DNS_RRS *rrs;
56 | DOMAIN_CACHE *dcache;
57 | TRANSPORT_CACHE *tcache;
58 | socklen_t addrlen;
59 | struct sockaddr_in source;
60 | char *pos, *head, *rear;
61 | char *buffer, domain[PACKAGE_SIZE], rbuffer[PACKAGE_SIZE];
62 | int size, dlen;
63 | time_t current;
64 | unsigned char qlen;
65 | unsigned int ttl, ttl_tmp;
66 | unsigned short index, q_len;
67 |
68 | ldns = &engine->local;
69 | rdns = &engine->remote;
70 | buffer = ldns->buffer + sizeof(unsigned short);
71 |
72 | addrlen = sizeof(struct sockaddr_in);
73 | size = recvfrom(ldns->sock, buffer, PACKAGE_SIZE, 0, (struct sockaddr*)&source, &addrlen);
74 | if(size <= (int)sizeof(DNS_HDR))
75 | return;
76 |
77 | hdr = (DNS_HDR*)buffer;
78 | rhdr = (DNS_HDR*)rbuffer;
79 | memset(rbuffer, 0, sizeof(DNS_HDR));
80 |
81 | rhdr->id = hdr->id;
82 | rhdr->qr = 1;
83 | q_len = 0;
84 | qds = NULL;
85 | head = buffer + sizeof(DNS_HDR);
86 | rear = buffer + size;
87 | if(hdr->qr != 0 || hdr->tc != 0 || ntohs(hdr->qd_count) != 1)
88 | rhdr->rcode = 1;
89 | else {
90 | dlen = 0;
91 | pos = head;
92 | while(pos < rear) {
93 | qlen = (unsigned char)*pos++;
94 | if(qlen > 63 || (pos + qlen) > (rear - sizeof(DNS_QDS))) {
95 | rhdr->rcode = 1;
96 | break;
97 | }
98 | if(qlen > 0) {
99 | if(dlen > 0)
100 | domain[dlen++] = '.';
101 | while(qlen-- > 0)
102 | domain[dlen++] = (char)tolower(*pos++);
103 | }
104 | else {
105 | qds = (DNS_QDS*) pos;
106 | if(ntohs(qds->classes) != 0x01)
107 | rhdr->rcode = 4;
108 | else {
109 | pos += sizeof(DNS_QDS);
110 | q_len = pos - head;
111 | }
112 | break;
113 | }
114 | }
115 | domain[dlen] = '\0';
116 | }
117 |
118 | if(rhdr->rcode == 0 && ntohs(qds->type) == 0x01) {
119 | dcache = domain_cache_search(domain);
120 | if(dcache) {
121 | rhdr->qd_count = htons(1);
122 | rhdr->an_count = htons(dcache->an_count);
123 | pos = rbuffer + sizeof(DNS_HDR);
124 | memcpy(pos, head, q_len);
125 | pos += q_len;
126 | memcpy(pos, dcache->answer, dcache->an_length);
127 | rear = pos + dcache->an_length;
128 | if(dcache->expire > 0) {
129 | if(time(¤t) <= dcache->timestamp)
130 | ttl = 1;
131 | else
132 | ttl = (unsigned int)(current - dcache->timestamp);
133 | index = 0;
134 | while(pos < rear && index++ < dcache->an_count) {
135 | rrs = NULL;
136 | if((unsigned char)*pos == 0xc0) {
137 | pos += 2;
138 | rrs = (DNS_RRS*) pos;
139 | }
140 | else {
141 | while(pos < rear) {
142 | qlen = (unsigned char)*pos++;
143 | if(qlen > 0)
144 | pos += qlen;
145 | else {
146 | rrs = (DNS_RRS*) pos;
147 | break;
148 | }
149 | }
150 | }
151 | ttl_tmp = ntohl(rrs->ttl);
152 | if(ttl_tmp <= ttl)
153 | ttl_tmp = 1;
154 | else
155 | ttl_tmp -= ttl;
156 | rrs->ttl = htonl(ttl_tmp);
157 | pos += sizeof(DNS_RRS) + ntohs(rrs->rd_length);
158 | }
159 | }
160 | sendto(ldns->sock, rbuffer, rear - rbuffer, 0, (struct sockaddr*)&source, sizeof(struct sockaddr_in));
161 | return;
162 | }
163 | }
164 |
165 | if(rhdr->rcode == 0) {
166 | tcache = transport_cache_insert(ntohs(hdr->id), &source, ldns);
167 | if(tcache == NULL)
168 | rhdr->rcode = 2;
169 | else {
170 | hdr->id = htons(tcache->new_id);
171 | if(!rdns->tcp) {
172 | if(sendto(rdns->sock, buffer, size, 0, (struct sockaddr*)&rdns->addr, sizeof(struct sockaddr_in)) != size)
173 | rhdr->rcode = 2;
174 | }
175 | else {
176 | if(rdns->sock == INVALID_SOCKET) {
177 | rdns->head = 0;
178 | rdns->rear = 0;
179 | rdns->sock = socket(AF_INET, SOCK_STREAM, 0);
180 | if(rdns->sock != INVALID_SOCKET) {
181 | setsockopt(rdns->sock, IPPROTO_TCP, TCP_NODELAY, (void*)&enable, sizeof(enable));
182 | if(connect(rdns->sock, (struct sockaddr*)&rdns->addr, sizeof(struct sockaddr_in)) != 0) {
183 | closesocket(rdns->sock);
184 | rdns->sock = INVALID_SOCKET;
185 | }
186 | }
187 | }
188 | if(rdns->sock == INVALID_SOCKET)
189 | rhdr->rcode = 2;
190 | else{
191 | pos = ldns->buffer;
192 | *(unsigned short*)pos = htons((unsigned short)size);
193 | size += sizeof(unsigned short);
194 | if(send(rdns->sock, ldns->buffer, size, 0) != size) {
195 | rdns->head = 0;
196 | rdns->rear = 0;
197 | closesocket(rdns->sock);
198 | rdns->sock = INVALID_SOCKET;
199 | rhdr->rcode = 2;
200 | }
201 | }
202 | }
203 | if(rhdr->rcode != 0)
204 | transport_cache_delete(tcache);
205 | }
206 | }
207 | if(rhdr->rcode != 0)
208 | sendto(ldns->sock, rbuffer, sizeof(DNS_HDR), 0, (struct sockaddr*)&source, sizeof(struct sockaddr_in));
209 | }
210 |
211 | static void process_response(char* buffer, int size)
212 | {
213 | DNS_HDR *hdr;
214 | DNS_QDS *qds;
215 | DNS_RRS *rrs;
216 | LOCAL_DNS *ldns;
217 | TRANSPORT_CACHE *cache;
218 | char domain[PACKAGE_SIZE];
219 | char *pos, *rear, *answer;
220 | int badfmt, dlen, length;
221 | unsigned char qlen;
222 | unsigned int ttl, ttl_tmp;
223 | unsigned short index, an_count;
224 |
225 | length = size;
226 | hdr = (DNS_HDR*)buffer;
227 | an_count = ntohs(hdr->an_count);
228 | if(hdr->qr == 1 && hdr->tc == 0 && ntohs(hdr->qd_count) == 1 && an_count > 0) {
229 | dlen = 0;
230 | qds = NULL;
231 | pos = buffer + sizeof(DNS_HDR);
232 | rear = buffer + size;
233 | while(pos < rear) {
234 | qlen = (unsigned char)*pos++;
235 | if(qlen > 63 || (pos + qlen) > (rear - sizeof(DNS_QDS)))
236 | break;
237 | if(qlen > 0) {
238 | if(dlen > 0)
239 | domain[dlen++] = '.';
240 | while(qlen-- > 0)
241 | domain[dlen++] = (char)tolower(*pos++);
242 | }
243 | else {
244 | qds = (DNS_QDS*) pos;
245 | if(ntohs(qds->classes) != 0x01)
246 | qds = NULL;
247 | else
248 | pos += sizeof(DNS_QDS);
249 | break;
250 | }
251 | }
252 | domain[dlen] = '\0';
253 |
254 | if(qds && ntohs(qds->type) == 0x01) {
255 | ttl = MAX_TTL;
256 | index = 0;
257 | badfmt = 0;
258 | answer = pos;
259 | while(badfmt == 0 && pos < rear && index++ < an_count) {
260 | rrs = NULL;
261 | if((unsigned char)*pos == 0xc0) {
262 | pos += 2;
263 | rrs = (DNS_RRS*) pos;
264 | }
265 | else {
266 | while(pos < rear) {
267 | qlen = (unsigned char)*pos++;
268 | if(qlen > 63 || (pos + qlen) > (rear - sizeof(DNS_RRS)))
269 | break;
270 | if(qlen > 0)
271 | pos += qlen;
272 | else {
273 | rrs = (DNS_RRS*) pos;
274 | break;
275 | }
276 | }
277 | }
278 | if(rrs == NULL || ntohs(rrs->classes) != 0x01)
279 | badfmt = 1;
280 | else {
281 | ttl_tmp = ntohl(rrs->ttl);
282 | if(ttl_tmp < ttl)
283 | ttl = ttl_tmp;
284 | pos += sizeof(DNS_RRS) + ntohs(rrs->rd_length);
285 | }
286 | }
287 | if(badfmt == 0) {
288 | hdr->nr_count = 0;
289 | hdr->ns_count = 0;
290 | length = pos - buffer;
291 | if(!disable_cache)
292 | domain_cache_append(domain, dlen, ttl, an_count, pos - answer, answer);
293 | }
294 | }
295 | }
296 |
297 | cache = transport_cache_search(ntohs(hdr->id));
298 | if(cache) {
299 | ldns = (LOCAL_DNS*)cache->context;
300 | hdr->id = htons(cache->old_id);
301 | sendto(ldns->sock, buffer, length, 0, (struct sockaddr*)&cache->source, sizeof(struct sockaddr_in));
302 | transport_cache_delete(cache);
303 | }
304 | }
305 |
306 | static void process_response_udp(REMOTE_DNS *rdns)
307 | {
308 | int size;
309 | socklen_t addrlen;
310 | struct sockaddr_in source;
311 |
312 | addrlen = sizeof(struct sockaddr_in);
313 | size = recvfrom(rdns->sock, rdns->buffer, PACKAGE_SIZE, 0, (struct sockaddr*)&source, &addrlen);
314 | if(size < (int)sizeof(DNS_HDR))
315 | return;
316 |
317 | if(source.sin_addr.s_addr != rdns->addr.sin_addr.s_addr)
318 | return;
319 |
320 | process_response(rdns->buffer, size);
321 | }
322 |
323 | static void process_response_tcp(REMOTE_DNS *rdns)
324 | {
325 | char *pos;
326 | int to_down, size;
327 | unsigned int len, buflen;
328 |
329 | to_down = 0;
330 | size = recv(rdns->sock, rdns->buffer + rdns->rear, rdns->capacity - rdns->rear, 0);
331 | if(size < 1)
332 | to_down = 1;
333 | else {
334 | rdns->rear += size;
335 | while((buflen = rdns->rear - rdns->head) > sizeof(unsigned short)) {
336 | pos = rdns->buffer + rdns->head;
337 | len = ntohs(*(unsigned short*)pos);
338 | if(len > PACKAGE_SIZE) {
339 | to_down = 1;
340 | break;
341 | }
342 | if(len + sizeof(unsigned short) > buflen)
343 | break;
344 | process_response(pos + sizeof(unsigned short), len);
345 | rdns->head += len + sizeof(unsigned short);
346 | }
347 | if(!to_down) {
348 | if(rdns->head == rdns->rear) {
349 | rdns->head = 0;
350 | rdns->rear = 0;
351 | }
352 | else if(rdns->head > PACKAGE_SIZE) {
353 | len = rdns->rear - rdns->head;
354 | memmove(rdns->buffer, rdns->buffer + rdns->head, len);
355 | rdns->head = 0;
356 | rdns->rear = len;
357 | }
358 | }
359 | }
360 |
361 | if(to_down){
362 | rdns->head = 0;
363 | rdns->rear = 0;
364 | closesocket(rdns->sock);
365 | rdns->sock = INVALID_SOCKET;
366 | }
367 | }
368 |
369 | static PROXY_ENGINE g_engine;
370 |
371 | static int dnsproxy(unsigned short local_port, const char* remote_addr, unsigned short remote_port, int remote_tcp)
372 | {
373 | int maxfd, fds;
374 | fd_set readfds;
375 | struct timeval timeout;
376 | struct sockaddr_in addr;
377 | time_t current, last_clean;
378 | #ifdef _WIN32
379 | BOOL bNewBehavior = FALSE;
380 | DWORD dwBytesReturned = 0;
381 | #endif
382 | PROXY_ENGINE *engine = &g_engine;
383 | LOCAL_DNS *ldns = &engine->local;
384 | REMOTE_DNS *rdns = &engine->remote;
385 |
386 | ldns->sock = socket(AF_INET, SOCK_DGRAM, 0);
387 | if(ldns->sock == INVALID_SOCKET) {
388 | perror("create socket");
389 | return -1;
390 | }
391 | setsockopt(ldns->sock, SOL_SOCKET, SO_REUSEADDR, (char*)&enable, sizeof(enable));
392 | #ifdef _WIN32
393 | WSAIoctl(ldns->sock, SIO_UDP_CONNRESET, &bNewBehavior, sizeof(bNewBehavior), NULL, 0, &dwBytesReturned, NULL, NULL);
394 | #endif
395 | memset(&addr, 0, sizeof(addr));
396 | addr.sin_family = AF_INET;
397 | addr.sin_addr.s_addr = INADDR_ANY;
398 | addr.sin_port = htons(local_port);
399 | if(bind(ldns->sock, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
400 | perror("bind service port");
401 | return -1;
402 | }
403 |
404 | rdns->tcp = remote_tcp;
405 | rdns->sock = INVALID_SOCKET;
406 | rdns->addr.sin_family = AF_INET;
407 | rdns->addr.sin_addr.s_addr = inet_addr(remote_addr);
408 | rdns->addr.sin_port = htons(remote_port);
409 | rdns->head = 0;
410 | rdns->rear = 0;
411 | rdns->capacity = sizeof(rdns->buffer);
412 | if(!rdns->tcp) {
413 | rdns->sock = socket(AF_INET, SOCK_DGRAM, 0);
414 | if(rdns->sock == INVALID_SOCKET) {
415 | perror("create socket");
416 | return -1;
417 | }
418 | #ifdef _WIN32
419 | WSAIoctl(rdns->sock, SIO_UDP_CONNRESET, &bNewBehavior, sizeof(bNewBehavior), NULL, 0, &dwBytesReturned, NULL, NULL);
420 | #endif
421 | }
422 |
423 | last_clean = time(¤t);
424 | while(1) {
425 | FD_ZERO(&readfds);
426 | FD_SET(ldns->sock, &readfds);
427 | maxfd = (int)ldns->sock;
428 | if(rdns->sock != INVALID_SOCKET) {
429 | FD_SET(rdns->sock, &readfds);
430 | if(maxfd < (int)rdns->sock)
431 | maxfd = (int)rdns->sock;
432 | }
433 | timeout.tv_sec = CACHE_CLEAN_TIME;
434 | timeout.tv_usec = 0;
435 | fds = select(maxfd + 1, &readfds, NULL, NULL, &timeout);
436 | if(fds > 0) {
437 | if(rdns->sock != INVALID_SOCKET
438 | && FD_ISSET(rdns->sock, &readfds)) {
439 | if(rdns->tcp)
440 | process_response_tcp(rdns);
441 | else
442 | process_response_udp(rdns);
443 | }
444 | if(FD_ISSET(ldns->sock, &readfds))
445 | process_query(engine);
446 | }
447 | if(time(¤t) - last_clean > CACHE_CLEAN_TIME || fds == 0) {
448 | last_clean = current;
449 | domain_cache_clean(current);
450 | transport_cache_clean(current);
451 | }
452 | }
453 | return 0;
454 | }
455 |
456 | struct xoption options[] = {
457 | {'v', "version", xargument_no, NULL, -1},
458 | {'h', "help", xargument_no, NULL, -1},
459 | {'d', "daemon", xargument_no, NULL, -1},
460 | {'p', "port", xargument_required, NULL, -1},
461 | {'T', "remote-tcp", xargument_no, NULL, -1},
462 | {'P', "remote-port", xargument_required, NULL, -1},
463 | {'R', "remote-addr", xargument_required, NULL, -1},
464 | {'f', "hosts-file", xargument_required, NULL, -1},
465 | {0, "disable-cache", xargument_no, &disable_cache, 1},
466 | {0, NULL, xargument_no, NULL, 0},
467 | };
468 |
469 | static void display_help()
470 | {
471 | printf("Usage: dnsproxy [options]\n"
472 | " -d or --daemon\n"
473 | " (daemon mode)\n"
474 | " -p or --port=\n"
475 | " (local bind port, default 53)\n"
476 | " -R or --remote-addr=\n"
477 | " (remote server ip, default 8.8.8.8)\n"
478 | " -P or --remote-port=\n"
479 | " (remote server port, default 53)\n"
480 | " -T or --remote-tcp\n"
481 | " (connect remote server in tcp, default no)\n"
482 | " -f or --hosts-file=\n"
483 | " (user-defined hosts file)\n"
484 | " -h, --help (print help and exit)\n"
485 | " -v, --version (print version and exit)\n");
486 | };
487 |
488 | int main(int argc, const char* argv[])
489 | {
490 | #ifdef _WIN32
491 | WSADATA wsaData;
492 | #endif
493 | int opt, optind;
494 | const char *optarg;
495 | int use_daemon = 0;
496 | int remote_tcp = 0;
497 | int transport_timeout = 5;
498 | const char *hosts_file = NULL;
499 | const char *remote_addr = "8.8.8.8";
500 | unsigned short local_port = 53, remote_port = 53;
501 |
502 | optind = 0;
503 | opt = xgetopt(argc, argv, options, &optind, &optarg);
504 | while(opt != -1) {
505 | switch(opt) {
506 | case 0:
507 | break;
508 | case 'p':
509 | local_port = (unsigned short)atoi(optarg);
510 | break;
511 | case 'P':
512 | remote_port = (unsigned short)atoi(optarg);
513 | break;
514 | case 'R':
515 | remote_addr = optarg;
516 | break;
517 | case 'T':
518 | remote_tcp = 1;
519 | break;
520 | case 'f':
521 | hosts_file = optarg;
522 | break;
523 | case 'd':
524 | use_daemon = 1;
525 | break;
526 | case 'v':
527 | printf("%s"
528 | " * version: %s\n",
529 | ascii_logo,
530 | VERSION);
531 | return 0;
532 | case 'h':
533 | default:
534 | display_help();
535 | return -1;
536 | }
537 | opt = xgetopt(argc, argv, options, &optind, &optarg);
538 | }
539 |
540 | #ifdef _WIN32
541 | WSAStartup(MAKEWORD(2,2), &wsaData);
542 | if(use_daemon) {
543 | freopen("NUL", "r", stdin);
544 | freopen("NUL", "w", stdout);
545 | freopen("NUL", "w", stderr);
546 | FreeConsole();
547 | }
548 | #else
549 | if(use_daemon) {
550 | int fd;
551 | pid_t pid = fork();
552 | if(pid < 0) {
553 | perror("fork");
554 | return -1;
555 | }
556 | if(pid != 0)
557 | exit(0);
558 | pid = setsid();
559 | if(pid < -1) {
560 | perror("setsid");
561 | return -1;
562 | }
563 | chdir("/");
564 | fd = open ("/dev/null", O_RDWR, 0);
565 | if(fd != -1) {
566 | dup2 (fd, 0);
567 | dup2 (fd, 1);
568 | dup2 (fd, 2);
569 | if(fd > 2)
570 | close (fd);
571 | }
572 | umask(0);
573 | }
574 | signal(SIGPIPE, SIG_IGN);
575 | #endif
576 |
577 | printf("%s"
578 | " * running at %d%s\n"
579 | " * transport to %s:%d,%s\n"
580 | , ascii_logo
581 | , local_port
582 | , disable_cache? ", cache: off": ""
583 | , remote_addr
584 | , remote_port
585 | , remote_tcp? "tcp": "udp");
586 | fflush(stdout);
587 |
588 | srand((unsigned int)time(NULL));
589 | domain_cache_init(hosts_file);
590 | transport_cache_init(transport_timeout);
591 | return dnsproxy(local_port, remote_addr, remote_port, remote_tcp);
592 | }
593 |
--------------------------------------------------------------------------------
/src/dnsproxy.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014, Vietor Liu
3 | *
4 | * This program is free software; you can redistribute it and/or
5 | * modify it under the terms of the GNU General Public License
6 | * as published by the Free Software Foundation; either version 2
7 | * of the License, or any later version. For full terms that can be
8 | * found in the LICENSE file.
9 | */
10 |
11 | #ifdef _WIN32
12 | #define _WIN32_WINNT 0x0501
13 | #define _CRT_SECURE_NO_WARNINGS
14 | #define WIN32_LEAN_AND_MEAN
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #define socklen_t int
21 | #else
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #define SOCKET int
37 | #define INVALID_SOCKET -1
38 | #define closesocket close
39 | #endif
40 |
41 | #include
42 | #include
43 | #include
44 | #include
45 | #include
46 |
47 | #include "embed/list.h"
48 | #include "embed/rbtree.h"
49 | #include "embed/xgetopt.h"
50 |
51 | #pragma pack(push,1)
52 |
53 | typedef struct {
54 | unsigned short id; // identification number
55 | unsigned char rd :1; // recursion desired
56 | unsigned char tc :1; // truncated message
57 | unsigned char aa :1; // authoritive answer
58 | unsigned char opcode :4; // purpose of message
59 | unsigned char qr :1; // query/response flag
60 | unsigned char rcode :4; // response code
61 | unsigned char cd :1; // checking disabled
62 | unsigned char ad :1; // authenticated data
63 | unsigned char z :1; // its z! reserved
64 | unsigned char ra :1; // recursion available
65 | unsigned short qd_count; // number of question entries
66 | unsigned short an_count; // number of answer entries
67 | unsigned short ns_count; // number of authority entries
68 | unsigned short nr_count; // number of resource entries
69 | } DNS_HDR;
70 |
71 | typedef struct {
72 | unsigned short type;
73 | unsigned short classes;
74 | } DNS_QDS;
75 |
76 | typedef struct {
77 | unsigned short type;
78 | unsigned short classes;
79 | unsigned int ttl;
80 | unsigned short rd_length;
81 | char rd_data[0];
82 | } DNS_RRS;
83 |
84 | #pragma pack(pop)
85 |
86 | #define MIN_TTL 10
87 | #define MAX_TTL (30 * 60)
88 |
89 | typedef struct {
90 | struct rbnode rb_name;
91 | union {
92 | struct {
93 | char *prefix;
94 | int p_length;
95 | int d_same;
96 | struct list_head lh_name;
97 | };
98 | struct {
99 | time_t expire;
100 | struct rbnode rb_expire;
101 | };
102 | };
103 | time_t timestamp;
104 | char *domain;
105 | int d_length;
106 | char *answer;
107 | unsigned short an_count;
108 | unsigned short an_length;
109 | char buffer[0];
110 | } DOMAIN_CACHE;
111 |
112 | void domain_cache_init(const char* file);
113 | DOMAIN_CACHE* domain_cache_search(char* domain);
114 | void domain_cache_append(char* domain, int d_length, unsigned int ttl, unsigned short an_count, unsigned short an_length, char *answer);
115 | void domain_cache_clean(time_t current);
116 |
117 | typedef struct {
118 | struct rbnode rb_new;
119 | struct list_head list;
120 | void *context;
121 | time_t expire;
122 | unsigned short new_id;
123 | unsigned short old_id;
124 | struct sockaddr_in source;
125 | } TRANSPORT_CACHE;
126 |
127 | void transport_cache_init(unsigned short timeout);
128 | TRANSPORT_CACHE* transport_cache_search(unsigned short new_id);
129 | TRANSPORT_CACHE* transport_cache_insert(unsigned short old_id, struct sockaddr_in *address, void *context);
130 | void transport_cache_delete(TRANSPORT_CACHE *cache);
131 | void transport_cache_clean(time_t current);
132 |
--------------------------------------------------------------------------------
/src/domain_cache.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014, Vietor Liu
3 | *
4 | * This program is free software; you can redistribute it and/or
5 | * modify it under the terms of the GNU General Public License
6 | * as published by the Free Software Foundation; either version 2
7 | * of the License, or any later version. For full terms that can be
8 | * found in the LICENSE file.
9 | */
10 |
11 | #include "dnsproxy.h"
12 |
13 | static struct {
14 | unsigned int count;
15 | unsigned int wcount;
16 | struct rbtree rb_name;
17 | struct rbtree rb_expire;
18 | struct list_head lh_name;
19 | } g_cache;
20 |
21 | typedef struct {
22 | char* domain;
23 | int length;
24 | } SEARCH_CONTEXT;
25 |
26 | static int name_search(const void* c, const struct rbnode* r)
27 | {
28 | DOMAIN_CACHE *right;
29 | SEARCH_CONTEXT *ctx = (SEARCH_CONTEXT*)c;
30 | right = rbtree_entry(r, DOMAIN_CACHE, rb_name);
31 | return strcmp(ctx->domain, right->domain);
32 | }
33 |
34 | static int name_compare(const struct rbnode* l, const struct rbnode* r)
35 | {
36 | DOMAIN_CACHE *left, *right;
37 | left = rbtree_entry(l, DOMAIN_CACHE, rb_name);
38 | right = rbtree_entry(r, DOMAIN_CACHE, rb_name);
39 | return strcmp(left->domain, right->domain);
40 | }
41 |
42 | static int wname_compare(const struct rbnode* l, const struct rbnode* r)
43 | {
44 | int ret, pos;
45 | DOMAIN_CACHE *left, *right;
46 | left = rbtree_entry(l, DOMAIN_CACHE, rb_name);
47 | right = rbtree_entry(r, DOMAIN_CACHE, rb_name);
48 | pos = left->d_length - right->d_length;
49 | if(pos > 0)
50 | ret = -1;
51 | else if(pos < 0)
52 | ret = 1;
53 | else {
54 | ret = strcmp(left->domain, right->domain);
55 | if(ret == 0) {
56 | pos = left->p_length - right->p_length;
57 | if(pos > 0)
58 | ret = -1;
59 | else if(pos < 0)
60 | ret = 1;
61 | else if(left->p_length == 0)
62 | ret = 0;
63 | else
64 | ret = strcmp(left->prefix, right->prefix);
65 | }
66 | }
67 | return ret;
68 | }
69 |
70 | static int expire_compare(const struct rbnode* l, const struct rbnode* r)
71 | {
72 | DOMAIN_CACHE *left, *right;
73 | left = rbtree_entry(l, DOMAIN_CACHE, rb_expire);
74 | right = rbtree_entry(r, DOMAIN_CACHE, rb_expire);
75 | return (int)(left->expire - right->expire);
76 | }
77 |
78 | static inline int is_space(char c)
79 | {
80 | return c == '\t' || c == ' ' || c == '\n' || c == '\r';
81 | }
82 |
83 | static char* skip_space(char* p)
84 | {
85 | while(*p && is_space(*p))
86 | ++p;
87 | return p;
88 | }
89 |
90 | static char* skip_to_space(char* p)
91 | {
92 | while(*p && !is_space(*p))
93 | ++p;
94 | return p;
95 | }
96 |
97 | static int name_append(struct rbtree *name_tree, char* domain, int d_length, unsigned short an_length, char *answer)
98 | {
99 | char *pos;
100 | struct rbnode *node;
101 | DOMAIN_CACHE *cache = (DOMAIN_CACHE*)calloc(1, sizeof(DOMAIN_CACHE) + d_length + 1 + an_length);
102 | if(cache) {
103 | time(&cache->timestamp);
104 | pos = cache->buffer;
105 | cache->domain = pos;
106 | cache->d_length = d_length;
107 | memcpy(cache->domain, domain, d_length);
108 | pos += d_length + 1;
109 | cache->answer = pos;
110 | cache->an_count = 1;
111 | cache->an_length = an_length;
112 | memcpy(cache->answer, answer, an_length);
113 | node = rbtree_insert_broken(name_tree, &cache->rb_name);
114 | if(node != RBNODE_NULL) {
115 | free(cache);
116 | cache = NULL;
117 | }
118 | }
119 | return cache != NULL? 1: 0;
120 | }
121 |
122 | static int wname_append(struct rbtree *name_tree, char* prefix, int p_length, char* domain, int d_length, unsigned short an_length, char *answer)
123 | {
124 | char *pos;
125 | struct rbnode *node;
126 | DOMAIN_CACHE *cache = (DOMAIN_CACHE*)calloc(1, sizeof(DOMAIN_CACHE) + p_length + d_length + 2 + an_length);
127 | if(cache) {
128 | pos = cache->buffer;
129 | cache->prefix = pos;
130 | cache->p_length = p_length;
131 | if(p_length > 0)
132 | memcpy(cache->prefix, prefix, p_length);
133 | pos += p_length + 1;
134 | cache->domain = pos;
135 | cache->d_length = d_length;
136 | if(d_length > 0)
137 | memcpy(cache->domain, domain, d_length);
138 | pos += d_length + 1;
139 | cache->answer = pos;
140 | cache->an_count = 1;
141 | cache->an_length = an_length;
142 | memcpy(cache->answer, answer, an_length);
143 | node = rbtree_insert_broken(name_tree, &cache->rb_name);
144 | if(node != RBNODE_NULL) {
145 | free(cache);
146 | cache = NULL;
147 | }
148 | }
149 | return cache != NULL? 1: 0;
150 | }
151 |
152 | void domain_cache_init(const char* hosts_file)
153 | {
154 | FILE *fp;
155 | DNS_QDS *qds;
156 | struct in_addr addr;
157 | unsigned short d_length, an_length;
158 | struct rbtree rb_wname;
159 | struct rbnode *node;
160 | DOMAIN_CACHE *cache, *cache1;
161 | char line[8192], answer[4096];
162 | char *rear, *rlimit, *ip, *domain, *pos, *wildcard;
163 |
164 | g_cache.count = 0;
165 | g_cache.wcount = 0;
166 | list_init(&g_cache.lh_name);
167 | rbtree_init(&g_cache.rb_name, name_search, name_compare);
168 | rbtree_init(&g_cache.rb_expire, NULL, expire_compare);
169 |
170 | if(hosts_file == NULL)
171 | return;
172 |
173 | rbtree_init(&rb_wname, NULL, wname_compare);
174 |
175 | memset(line, 0, sizeof(line));
176 | fp = fopen(hosts_file, "r");
177 | if(fp) {
178 | while(fgets(line, sizeof(line) - 1, fp)) {
179 | rlimit = line + strlen(line);
180 |
181 | ip = skip_space(line);
182 | if(is_space(*ip) || *ip == '#')
183 | continue;
184 | rear = skip_to_space(ip);
185 | if(!is_space(*rear))
186 | continue;
187 | *rear = '\0';
188 | addr.s_addr = inet_addr(ip);
189 | if(addr.s_addr == INADDR_NONE || addr.s_addr == INADDR_ANY)
190 | continue;
191 |
192 | pos = answer;
193 | *pos++ = 0xc0;
194 | *pos++ = 0x0c;
195 | qds = (DNS_QDS*)pos;
196 | qds->type = htons(0x01);
197 | qds->classes = htons(0x01);
198 | pos += sizeof(DNS_QDS);
199 | *(unsigned int*)pos = htonl(MAX_TTL);
200 | pos += sizeof(unsigned int);
201 | *(unsigned short*)pos = htons(sizeof(addr));
202 | pos += sizeof(unsigned short);
203 | memcpy(pos, &addr, sizeof(addr));
204 | pos += sizeof(addr);
205 | an_length = pos - answer;
206 |
207 | while(rear + 1 < rlimit) {
208 | domain = skip_space(rear + 1);
209 | if(is_space(*domain))
210 | break;
211 | rear = skip_to_space(domain);
212 | if(*rear && is_space(*rear))
213 | *rear = '\0';
214 |
215 | pos = domain;
216 | while(*pos) {
217 | *pos = (char)tolower(*pos);
218 | ++ pos;
219 | }
220 | wildcard = strchr(domain, '*');
221 | if(wildcard) {
222 | *wildcard++ = '\0';
223 | if(wname_append(&rb_wname, domain, wildcard - domain - 1, wildcard, rear - wildcard, an_length, answer))
224 | g_cache.wcount++;
225 | }
226 | else {
227 | d_length = rear - domain;
228 | if(name_append(&g_cache.rb_name, domain, d_length, an_length, answer))
229 | g_cache.count++;
230 | }
231 | }
232 | }
233 | fclose(fp);
234 | }
235 |
236 | while((node = rbtree_last(&rb_wname)) != RBNODE_NULL) {
237 | rbtree_delete(&rb_wname, node);
238 | cache = rbtree_entry(node, DOMAIN_CACHE, rb_name);
239 | if(!list_empty(&g_cache.lh_name)) {
240 | cache1 = list_first(&g_cache.lh_name, DOMAIN_CACHE, lh_name);
241 | if(cache1->d_length <= cache->d_length
242 | && strncmp(cache1->domain, cache->domain + (cache->d_length - cache1->d_length), cache1->d_length) == 0)
243 | cache1->d_same = 1;
244 | }
245 | list_insert(&g_cache.lh_name, &cache->lh_name);
246 | }
247 | }
248 |
249 | DOMAIN_CACHE* domain_cache_search(char* domain)
250 | {
251 | int pos, pos1, same;
252 | SEARCH_CONTEXT ctx;
253 | struct rbnode *node;
254 | DOMAIN_CACHE *cache, *cache1;
255 | ctx.domain = domain;
256 | ctx.length = strlen(domain);
257 | node = rbtree_search(&g_cache.rb_name, &ctx);
258 | if(node == RBNODE_NULL) {
259 | if(g_cache.wcount < 1)
260 | return NULL;
261 | same = 0;
262 | cache1 = NULL;
263 | list_for_each(cache, &g_cache.lh_name, DOMAIN_CACHE, lh_name) {
264 | pos = ctx.length - cache->d_length;
265 | if(same)
266 | same = cache->d_same;
267 | if(same || (pos >= 0 && strcmp(ctx.domain + pos, cache->domain) == 0)) {
268 | same = 1;
269 | if(cache->p_length == 0) {
270 | cache1 = cache;
271 | break;
272 | }
273 | pos1 = pos - cache->p_length;
274 | if(pos1 >= 0 && strncmp(ctx.domain, cache->prefix, cache->p_length) == 0) {
275 | cache1 = cache;
276 | break;
277 | }
278 | }
279 | }
280 | if(cache1 == NULL)
281 | return NULL;
282 | node = &cache1->rb_name;
283 | }
284 | return rbtree_entry(node, DOMAIN_CACHE, rb_name);
285 | }
286 |
287 | void domain_cache_append(char* domain, int d_length, unsigned int ttl, unsigned short an_count, unsigned short an_length, char *answer)
288 | {
289 | struct rbnode *node;
290 | DOMAIN_CACHE *cache = (DOMAIN_CACHE*)calloc(1, sizeof(DOMAIN_CACHE) + d_length + 1 + an_length);
291 | if(cache) {
292 | time(&cache->timestamp);
293 | cache->expire = cache->timestamp + ttl;
294 | cache->domain = cache->buffer;
295 | cache->answer = cache->buffer + d_length + 1;
296 | cache->d_length = d_length;
297 | memcpy(cache->domain, domain, d_length);
298 | cache->an_count = an_count;
299 | cache->an_length = an_length;
300 | memcpy(cache->answer, answer, an_length);
301 | node = rbtree_insert_broken(&g_cache.rb_name, &cache->rb_name);
302 | if(node != RBNODE_NULL)
303 | free(cache);
304 | else
305 | {
306 | ++g_cache.count;
307 | rbtree_insert(&g_cache.rb_expire, &cache->rb_expire);
308 | }
309 | }
310 | }
311 |
312 | void domain_cache_clean(time_t current)
313 | {
314 | DOMAIN_CACHE* cache;
315 | struct rbnode *node;
316 |
317 | while(!rbtree_empty(&g_cache.rb_expire)) {
318 | node = rbtree_first(&g_cache.rb_expire);
319 | cache = rbtree_entry(node, DOMAIN_CACHE, rb_expire);
320 | if(cache->expire > current)
321 | break;
322 | --g_cache.count;
323 | rbtree_delete(&g_cache.rb_name, &cache->rb_name);
324 | rbtree_delete(&g_cache.rb_expire, &cache->rb_expire);
325 | free(cache);
326 | }
327 | }
328 |
--------------------------------------------------------------------------------
/src/embed/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013-2014, Vietor Liu
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without modification,
5 | are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice, this
11 | list of conditions and the following disclaimer in the documentation and/or
12 | other materials provided with the distribution.
13 |
14 | * Neither the name of the copyright owners nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/src/embed/embed.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014, Vietor Liu
3 | * All rights reserved.
4 | * Use of this source code is governed by a BSD-style license that can be
5 | * found in the LICENSE file.
6 | */
7 |
8 | #ifndef EMBED_H
9 | #define EMBED_H
10 |
11 | #ifdef __cplusplus
12 | #error "Just only support c language"
13 | #endif
14 |
15 | #ifndef NULL
16 | #define NULL ((void*)0)
17 | #endif
18 |
19 | #if defined(__GNUC__)
20 |
21 | #if defined(__LP64__)
22 | #define __BIT64__
23 | #endif
24 |
25 | #define likely(x) __builtin_expect(!!(x), 1)
26 | #define unlikely(x) __builtin_expect(!!(x), 0)
27 | #define inline_always __inline__ __attribute__((always_inline))
28 |
29 | #define container_of(ptr, type, member) \
30 | ({const typeof( ((type *)0)->member ) *__mptr = (ptr); \
31 | (type *)( (char *)__mptr - __builtin_offsetof(type,member) );})
32 |
33 | #elif defined(_MSC_VER)
34 |
35 | #if defined(_M_X64)
36 | #define __BIT64__
37 | #endif
38 |
39 | #define likely(x) (x)
40 | #define unlikely(x) (x)
41 | #define inline __inline
42 | #define inline_always __forceinline
43 |
44 | #define container_of(ptr, type, member) \
45 | (type *)((char *)ptr - (unsigned int)(&(((type *)0)->member)))
46 |
47 | #else
48 | #error "Unsupported compiler version"
49 | #endif
50 |
51 | #endif
52 |
--------------------------------------------------------------------------------
/src/embed/list.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014, Vietor Liu
3 | * All rights reserved.
4 | * Use of this source code is governed by a BSD-style license that can be
5 | * found in the LICENSE file.
6 | */
7 |
8 | #ifndef LIST_H
9 | #define LIST_H
10 |
11 | #include "embed.h"
12 |
13 | struct list_head {
14 | struct list_head *prev;
15 | struct list_head *next;
16 | };
17 |
18 | static inline void list_init(struct list_head *list)
19 | {
20 | list->prev = list;
21 | list->next = list;
22 | }
23 |
24 | static inline void list_insert(struct list_head *list, struct list_head *elm)
25 | {
26 | elm->prev = list;
27 | elm->next = list->next;
28 | list->next = elm;
29 | elm->next->prev = elm;
30 | }
31 |
32 | static inline void list_remove(struct list_head *elm)
33 | {
34 | elm->prev->next = elm->next;
35 | elm->next->prev = elm->prev;
36 | list_init(elm);
37 | }
38 |
39 | static inline int list_empty(const struct list_head *list)
40 | {
41 | return list->next == list;
42 | }
43 |
44 | static inline void list_insert_list(struct list_head *list, struct list_head *other)
45 | {
46 | if (list_empty(other))
47 | return;
48 |
49 | other->next->prev = list;
50 | other->prev->next = list->next;
51 | list->next->prev = other->prev;
52 | list->next = other->next;
53 | list_init(other);
54 | }
55 |
56 | #define list_first(ptr, type, member) \
57 | container_of((ptr)->next, type, member)
58 |
59 | #define list_for_each(pos, head, type, member) \
60 | for (pos = 0, pos = container_of((head)->next, type, member); \
61 | &pos->member != (head); \
62 | pos = container_of(pos->member.next, type, member))
63 |
64 | #define list_for_each_safe(pos, tmp, head, type, member) \
65 | for (pos = 0, tmp = 0, \
66 | pos = container_of((head)->next, type, member), \
67 | tmp = container_of((pos)->member.next, type, member); \
68 | &pos->member != (head); \
69 | pos = tmp, \
70 | tmp = container_of(pos->member.next, type, member))
71 |
72 | #define list_for_each_reverse(pos, head, type, member) \
73 | for (pos = 0, pos = container_of((head)->prev, type, member); \
74 | &pos->member != (head); \
75 | pos = container_of(pos->member.prev, type, member))
76 |
77 | #define list_for_each_reverse_safe(pos, tmp, head, type, member) \
78 | for (pos = 0, tmp = 0, \
79 | pos = container_of((head)->prev, type, member), \
80 | tmp = container_of((pos)->member.prev, type, member); \
81 | &pos->member != (head); \
82 | pos = tmp, \
83 | tmp = container_of(pos->member.prev, type, member))
84 |
85 | #endif
86 |
--------------------------------------------------------------------------------
/src/embed/rbtree.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014, Vietor Liu
3 | * All rights reserved.
4 | * Use of this source code is governed by a BSD-style license that can be
5 | * found in the LICENSE file.
6 | *
7 | * Redistribution source code with modification from
8 | * http://ftp.cc.uoc.gr/mirrors/OpenBSD/src/usr.sbin/nsd/rbtree.c
9 | * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
10 | * It's BSD-style license, See detail from
11 | * http://ftp.cc.uoc.gr/mirrors/OpenBSD/src/usr.sbin/nsd/LICENSE
12 | *
13 | */
14 |
15 | #include "rbtree.h"
16 |
17 | struct rbnode rbnode_null = {
18 | &rbnode_null,
19 | &rbnode_null,
20 | &rbnode_null,
21 | RBCOLOR_BLACK
22 | };
23 |
24 | static void rbtree_rotate_left(struct rbtree *rbtree, struct rbnode *node)
25 | {
26 | struct rbnode *right = node->right;
27 |
28 | node->right = right->left;
29 | if (right->left != RBNODE_NULL)
30 | right->left->parent = node;
31 |
32 | right->parent = node->parent;
33 |
34 | if (node->parent != RBNODE_NULL) {
35 | if (node == node->parent->left) {
36 | node->parent->left = right;
37 | } else {
38 | node->parent->right = right;
39 | }
40 | } else {
41 | rbtree->root = right;
42 | }
43 | right->left = node;
44 | node->parent = right;
45 | }
46 |
47 | static void rbtree_rotate_right(struct rbtree *rbtree, struct rbnode *node)
48 | {
49 | struct rbnode *left = node->left;
50 |
51 | node->left = left->right;
52 | if (left->right != RBNODE_NULL)
53 | left->right->parent = node;
54 |
55 | left->parent = node->parent;
56 |
57 | if (node->parent != RBNODE_NULL) {
58 | if (node == node->parent->right) {
59 | node->parent->right = left;
60 | } else {
61 | node->parent->left = left;
62 | }
63 | } else {
64 | rbtree->root = left;
65 | }
66 | left->right = node;
67 | node->parent = left;
68 | }
69 |
70 | static void rbtree_insert_balance(struct rbtree *rbtree, struct rbnode *node)
71 | {
72 | struct rbnode *uncle;
73 |
74 | while (node != rbtree->root && node->parent->color == RBCOLOR_RED) {
75 | if (node->parent == node->parent->parent->left) {
76 | uncle = node->parent->parent->right;
77 |
78 | if (uncle->color == RBCOLOR_RED) {
79 | node->parent->color = RBCOLOR_BLACK;
80 | uncle->color = RBCOLOR_BLACK;
81 | node->parent->parent->color = RBCOLOR_RED;
82 | node = node->parent->parent;
83 | } else {
84 | if (node == node->parent->right) {
85 | node = node->parent;
86 | rbtree_rotate_left(rbtree, node);
87 | }
88 | node->parent->color = RBCOLOR_BLACK;
89 | node->parent->parent->color = RBCOLOR_RED;
90 | rbtree_rotate_right(rbtree, node->parent->parent);
91 | }
92 | } else {
93 | uncle = node->parent->parent->left;
94 |
95 | if (uncle->color == RBCOLOR_RED) {
96 | node->parent->color = RBCOLOR_BLACK;
97 | uncle->color = RBCOLOR_BLACK;
98 | node->parent->parent->color = RBCOLOR_RED;
99 | node = node->parent->parent;
100 | } else {
101 | if (node == node->parent->left) {
102 | node = node->parent;
103 | rbtree_rotate_right(rbtree, node);
104 | }
105 | node->parent->color = RBCOLOR_BLACK;
106 | node->parent->parent->color = RBCOLOR_RED;
107 | rbtree_rotate_left(rbtree, node->parent->parent);
108 | }
109 | }
110 | }
111 | rbtree->root->color = RBCOLOR_BLACK;
112 | }
113 |
114 | static inline void change_parent_ptr(struct rbtree* rbtree, struct rbnode* parent, struct rbnode* old, struct rbnode* new)
115 | {
116 | if(parent == RBNODE_NULL)
117 | {
118 | if(rbtree->root == old) rbtree->root = new;
119 | return;
120 | }
121 | if(parent->left == old) parent->left = new;
122 | if(parent->right == old) parent->right = new;
123 | }
124 |
125 | struct rbnode *rbtree_insert3(struct rbtree *rbtree, struct rbnode *data, int flag)
126 | {
127 | int r = 0;
128 | struct rbnode *node = rbtree->root;
129 | struct rbnode *parent = RBNODE_NULL;
130 |
131 | while (node != RBNODE_NULL) {
132 | parent = node;
133 | r = rbtree->compare(data, node);
134 |
135 | if (r < 0)
136 | node = node->left;
137 | else if(r > 0 || flag == 0)
138 | node = node->right;
139 | else if(flag == 1) {
140 | /* return exists node */
141 | rbnode_init(data);
142 | return node;
143 | }
144 | else { /* flag == 2 */
145 | /* return and replace exists node */
146 | data->left = node->left;
147 | data->right = node->right;
148 | data->color = node->color;
149 | if(node->left != RBNODE_NULL)
150 | node->left->parent = data;
151 | if(node->right != RBNODE_NULL)
152 | node->right->parent = data;
153 | data->parent = node->parent;
154 | change_parent_ptr(rbtree, node->parent, node, data);
155 | rbnode_init(node);
156 | return node;
157 | }
158 | }
159 |
160 | data->parent = parent;
161 | data->left = data->right = RBNODE_NULL;
162 | data->color = RBCOLOR_RED;
163 |
164 | if (parent != RBNODE_NULL) {
165 | if (r < 0) {
166 | parent->left = data;
167 | } else {
168 | parent->right = data;
169 | }
170 | } else {
171 | rbtree->root = data;
172 | }
173 | rbtree_insert_balance(rbtree, data);
174 | return RBNODE_NULL;
175 | }
176 |
177 | static inline void swap_ul(unsigned long* x, unsigned long* y)
178 | {
179 | unsigned long t = *x; *x = *y; *y = t;
180 | }
181 |
182 | static inline void swap_np(struct rbnode** x, struct rbnode** y)
183 | {
184 | struct rbnode* t = *x; *x = *y; *y = t;
185 | }
186 |
187 | static inline void change_child_ptr(struct rbnode* child, struct rbnode* old, struct rbnode* new)
188 | {
189 | if(child == RBNODE_NULL)
190 | return;
191 | if(child->parent == old)
192 | child->parent = new;
193 | }
194 |
195 | static void rbtree_delete_balance(struct rbtree* rbtree, struct rbnode* child, struct rbnode* child_parent)
196 | {
197 | struct rbnode* sibling;
198 | int go_up = 1;
199 |
200 | if(child_parent->right == child)
201 | sibling = child_parent->left;
202 | else
203 | sibling = child_parent->right;
204 |
205 | while(go_up)
206 | {
207 | if(child_parent == RBNODE_NULL)
208 | return;
209 |
210 | if(sibling->color == RBCOLOR_RED)
211 | {
212 | child_parent->color = RBCOLOR_RED;
213 | sibling->color = RBCOLOR_BLACK;
214 | if(child_parent->right == child)
215 | rbtree_rotate_right(rbtree, child_parent);
216 | else
217 | rbtree_rotate_left(rbtree, child_parent);
218 | if(child_parent->right == child)
219 | sibling = child_parent->left;
220 | else
221 | sibling = child_parent->right;
222 | }
223 |
224 | if(child_parent->color == RBCOLOR_BLACK
225 | && sibling->color == RBCOLOR_BLACK
226 | && sibling->left->color == RBCOLOR_BLACK
227 | && sibling->right->color == RBCOLOR_BLACK)
228 | {
229 | if(sibling != RBNODE_NULL)
230 | sibling->color = RBCOLOR_RED;
231 | child = child_parent;
232 | child_parent = child_parent->parent;
233 | if(child_parent->right == child)
234 | sibling = child_parent->left;
235 | else
236 | sibling = child_parent->right;
237 | }
238 | else
239 | go_up = 0;
240 | }
241 |
242 | if(child_parent->color == RBCOLOR_RED
243 | && sibling->color == RBCOLOR_BLACK
244 | && sibling->left->color == RBCOLOR_BLACK
245 | && sibling->right->color == RBCOLOR_BLACK)
246 | {
247 | if(sibling != RBNODE_NULL)
248 | sibling->color = RBCOLOR_RED;
249 | child_parent->color = RBCOLOR_BLACK;
250 | return;
251 | }
252 |
253 | if(child_parent->right == child
254 | && sibling->color == RBCOLOR_BLACK
255 | && sibling->right->color == RBCOLOR_RED
256 | && sibling->left->color == RBCOLOR_BLACK)
257 | {
258 | sibling->color = RBCOLOR_RED;
259 | sibling->right->color = RBCOLOR_BLACK;
260 | rbtree_rotate_left(rbtree, sibling);
261 | if(child_parent->right == child)
262 | sibling = child_parent->left;
263 | else
264 | sibling = child_parent->right;
265 | }
266 | else if(child_parent->left == child
267 | && sibling->color == RBCOLOR_BLACK
268 | && sibling->left->color == RBCOLOR_RED
269 | && sibling->right->color == RBCOLOR_BLACK)
270 | {
271 | sibling->color = RBCOLOR_RED;
272 | sibling->left->color = RBCOLOR_BLACK;
273 | rbtree_rotate_right(rbtree, sibling);
274 | if(child_parent->right == child)
275 | sibling = child_parent->left;
276 | else
277 | sibling = child_parent->right;
278 | }
279 |
280 | sibling->color = child_parent->color;
281 | child_parent->color = RBCOLOR_BLACK;
282 | if(child_parent->right == child)
283 | {
284 | sibling->left->color = RBCOLOR_BLACK;
285 | rbtree_rotate_right(rbtree, child_parent);
286 | }
287 | else
288 | {
289 | sibling->right->color = RBCOLOR_BLACK;
290 | rbtree_rotate_left(rbtree, child_parent);
291 | }
292 | }
293 |
294 | void rbtree_delete(struct rbtree *rbtree, struct rbnode *to_delete)
295 | {
296 | struct rbnode *child;
297 |
298 | if(rbnode_empty(to_delete))
299 | return;
300 |
301 | if(to_delete->left != RBNODE_NULL &&
302 | to_delete->right != RBNODE_NULL)
303 | {
304 | struct rbnode *smright = to_delete->right;
305 |
306 | while(smright->left != RBNODE_NULL)
307 | smright = smright->left;
308 |
309 | swap_ul(&to_delete->color, &smright->color);
310 |
311 | change_parent_ptr(rbtree, to_delete->parent, to_delete, smright);
312 | if(to_delete->right != smright)
313 | change_parent_ptr(rbtree, smright->parent, smright, to_delete);
314 |
315 | change_child_ptr(smright->left, smright, to_delete);
316 | change_child_ptr(smright->left, smright, to_delete);
317 | change_child_ptr(smright->right, smright, to_delete);
318 | change_child_ptr(smright->right, smright, to_delete);
319 | change_child_ptr(to_delete->left, to_delete, smright);
320 | if(to_delete->right != smright)
321 | change_child_ptr(to_delete->right, to_delete, smright);
322 | if(to_delete->right == smright)
323 | {
324 | to_delete->right = to_delete;
325 | smright->parent = smright;
326 | }
327 |
328 | swap_np(&to_delete->parent, &smright->parent);
329 | swap_np(&to_delete->left, &smright->left);
330 | swap_np(&to_delete->right, &smright->right);
331 | }
332 |
333 | if(to_delete->left != RBNODE_NULL)
334 | child = to_delete->left;
335 | else
336 | child = to_delete->right;
337 |
338 | change_parent_ptr(rbtree, to_delete->parent, to_delete, child);
339 | change_child_ptr(child, to_delete, to_delete->parent);
340 |
341 | if(to_delete->color == RBCOLOR_RED)
342 | ;
343 | else if(child->color == RBCOLOR_RED) {
344 | if(child!=RBNODE_NULL)
345 | child->color = RBCOLOR_BLACK;
346 | }
347 | else
348 | rbtree_delete_balance(rbtree, child, to_delete->parent);
349 |
350 | rbnode_init(to_delete);
351 | }
352 |
353 | struct rbnode* rbtree_first (struct rbtree *rbtree)
354 | {
355 | struct rbnode *node = rbtree->root;
356 |
357 | if (rbtree->root != RBNODE_NULL) {
358 | for (node = rbtree->root;
359 | node->left != RBNODE_NULL;
360 | node = node->left);
361 | }
362 | return node;
363 | }
364 |
365 | struct rbnode* rbtree_last (struct rbtree *rbtree)
366 | {
367 | struct rbnode *node = rbtree->root;
368 |
369 | if (rbtree->root != RBNODE_NULL) {
370 | for (node = rbtree->root;
371 | node->right != RBNODE_NULL;
372 | node = node->right);
373 | }
374 | return node;
375 | }
376 |
377 | struct rbnode* rbtree_next (struct rbnode *node)
378 | {
379 | struct rbnode *parent;
380 |
381 | if (node->right != RBNODE_NULL) {
382 | for (node = node->right;
383 | node->left != RBNODE_NULL;
384 | node = node->left);
385 | } else {
386 | parent = node->parent;
387 | while (parent != RBNODE_NULL && node == parent->right) {
388 | node = parent;
389 | parent = parent->parent;
390 | }
391 | node = parent;
392 | }
393 | return node;
394 | }
395 |
396 | struct rbnode* rbtree_previous(struct rbnode *node)
397 | {
398 | struct rbnode *parent;
399 |
400 | if (node->left != RBNODE_NULL) {
401 | for (node = node->left;
402 | node->right != RBNODE_NULL;
403 | node = node->right);
404 | } else {
405 | parent = node->parent;
406 | while (parent != RBNODE_NULL && node == parent->left) {
407 | node = parent;
408 | parent = parent->parent;
409 | }
410 | node = parent;
411 | }
412 | return node;
413 | }
414 |
415 | struct rbnode *rbtree_search (struct rbtree *rbtree, void *context)
416 | {
417 | int r = 0;
418 | struct rbnode *node = rbtree->root;
419 |
420 | while (node != RBNODE_NULL) {
421 | r = rbtree->search(context, node);
422 | if(r == 0)
423 | return node;
424 | else if (r < 0) {
425 | node = node->left;
426 | } else {
427 | node = node->right;
428 | }
429 | }
430 | return RBNODE_NULL;
431 | }
432 |
--------------------------------------------------------------------------------
/src/embed/rbtree.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014, Vietor Liu
3 | * All rights reserved.
4 | * Use of this source code is governed by a BSD-style license that can be
5 | * found in the LICENSE file.
6 | */
7 |
8 | #ifndef RBTREE_H
9 | #define RBTREE_H
10 |
11 | #include "embed.h"
12 |
13 | enum { RBCOLOR_BLACK, RBCOLOR_RED };
14 |
15 | struct rbnode {
16 | struct rbnode *parent;
17 | struct rbnode *left;
18 | struct rbnode *right;
19 | unsigned long color;
20 | };
21 |
22 | struct rbtree {
23 | struct rbnode *root;
24 | int (*search) (const void*, const struct rbnode*);
25 | int (*compare) (const struct rbnode*, const struct rbnode*);
26 | };
27 |
28 | extern struct rbnode rbnode_null;
29 | #define RBNODE_NULL (&rbnode_null)
30 | #define RBNODE_EMPTY ((void *)0)
31 |
32 | #define rbtree_entry(ptr, type, member) \
33 | container_of(ptr, type, member)
34 |
35 | #define rbnode_entry(ptr, type, member) \
36 | container_of(ptr, type, member)
37 |
38 | static inline void rbtree_init(struct rbtree *rbtree,
39 | int (*search)(const void*, const struct rbnode*),
40 | int (*compare)(const struct rbnode*, const struct rbnode*))
41 | {
42 | rbtree->root = RBNODE_NULL;
43 | rbtree->search = search;
44 | rbtree->compare = compare;
45 | }
46 |
47 | static inline int rbtree_empty(struct rbtree *rbtree)
48 | {
49 | return rbtree->root == RBNODE_NULL;
50 | }
51 |
52 | static inline void rbnode_init(struct rbnode *rbnode)
53 | {
54 | rbnode->parent = RBNODE_EMPTY;
55 | rbnode->left = RBNODE_EMPTY;
56 | rbnode->right = RBNODE_EMPTY;
57 | rbnode->color = RBCOLOR_BLACK;
58 | }
59 |
60 | static inline int rbnode_empty(struct rbnode *rbnode)
61 | {
62 | return rbnode->parent == RBNODE_EMPTY;
63 | }
64 |
65 | void rbtree_delete(struct rbtree *rbtree, struct rbnode *data);
66 | struct rbnode *rbtree_insert3(struct rbtree *rbtree, struct rbnode *data, int flag);
67 |
68 | static inline void rbtree_insert(struct rbtree *rbtree, struct rbnode *data)
69 | {
70 | rbtree_insert3(rbtree, data, 0);
71 | }
72 |
73 | static inline struct rbnode *rbtree_insert_broken(struct rbtree *rbtree, struct rbnode *data)
74 | {
75 | return rbtree_insert3(rbtree, data, 1);
76 | }
77 |
78 | static inline struct rbnode *rbtree_insert_replace(struct rbtree *rbtree, struct rbnode *data)
79 | {
80 | return rbtree_insert3(rbtree, data, 2);
81 | }
82 |
83 | struct rbnode *rbtree_first(struct rbtree *rbtree);
84 | struct rbnode *rbtree_last(struct rbtree *rbtree);
85 | struct rbnode *rbtree_next(struct rbnode *rbtree);
86 | struct rbnode *rbtree_previous(struct rbnode *rbtree);
87 | struct rbnode *rbtree_search (struct rbtree *rbtree, void *context);
88 |
89 | #endif
90 |
--------------------------------------------------------------------------------
/src/embed/xgetopt.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014, Vietor Liu
3 | * All rights reserved.
4 | * Use of this source code is governed by a BSD-style license that can be
5 | * found in the LICENSE file.
6 | */
7 |
8 | #include "xgetopt.h"
9 |
10 | #include
11 | #include
12 |
13 | #define BADCH '?'
14 | #define BADARG ':'
15 |
16 | static const char *__progname(const char* name)
17 | {
18 | const char *tmp = strrchr(name, '/');
19 | #ifdef _WIN32
20 | if(tmp == NULL)
21 | tmp = strrchr(name, '\\');
22 | #endif
23 | return tmp != NULL? tmp + 1: name;
24 | }
25 |
26 | int xgetopt(int argc, const char* argv[], const struct xoption* options, int* optind, const char **optarg)
27 | {
28 | int i, val, match, name_len;
29 | const char *cur_argv, *embed_arg;
30 |
31 | if(argc < 1 || argv == NULL || options == NULL || optind == NULL || optarg == NULL)
32 | return -1;
33 |
34 | if(*optind < 1)
35 | *optind = 1;
36 | *optarg = NULL;
37 |
38 | if(*optind >= argc)
39 | return -1;
40 |
41 | match = -1;
42 | embed_arg = NULL;
43 | cur_argv = argv[(*optind)++];
44 | if(*cur_argv == '-') {
45 | if(*(++cur_argv) != '-') {
46 | if(*(cur_argv + 1) != '\0')
47 | embed_arg = cur_argv + 1;
48 | for(i = 0; options[i].opt != 0 || options[i].name; ++i) {
49 | if(options[i].opt == 0)
50 | continue;
51 | if(*cur_argv == options[i].opt) {
52 | match = i;
53 | break;
54 | }
55 | }
56 | }
57 | else {
58 | ++cur_argv;
59 | if ((embed_arg = strchr(cur_argv, '=')) == NULL)
60 | name_len = strlen(cur_argv);
61 | else {
62 | name_len = embed_arg - cur_argv;
63 | ++embed_arg;
64 | }
65 | for(i = 0; options[i].opt != 0 || options[i].name; ++i) {
66 | if(strncmp(cur_argv, options[i].name, name_len))
67 | continue;
68 | if(strlen(options[i].name) == name_len) {
69 | match = i;
70 | break;
71 | }
72 | }
73 | }
74 | }
75 | if(match == -1) {
76 | (void)fprintf(stderr, "%s: illegal option -- %s\n", __progname(argv[0]), cur_argv);
77 | return BADCH;
78 | }
79 |
80 | if(options[match].has_arg == xargument_optional
81 | || options[match].has_arg == xargument_required) {
82 | if(embed_arg)
83 | *optarg = embed_arg;
84 | else if(*optind < argc && argv[*optind][0] != '-')
85 | *optarg = argv[(*optind)++];
86 | else if(options[match].has_arg == xargument_required) {
87 | (void)fprintf(stderr, "%s: option requires an argument -- %s\n", __progname(argv[0]), cur_argv);
88 | return BADARG;
89 | }
90 | }
91 |
92 | if(options[match].val == -1)
93 | val = (int)options[i].opt;
94 | else
95 | val = options[match].val;
96 |
97 | if(options[match].flag) {
98 | *options[match].flag = val;
99 | return 0;
100 | }
101 | return val;
102 | }
103 |
--------------------------------------------------------------------------------
/src/embed/xgetopt.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014, Vietor Liu
3 | * All rights reserved.
4 | * Use of this source code is governed by a BSD-style license that can be
5 | * found in the LICENSE file.
6 | */
7 |
8 | #ifndef XGETOPT_H
9 | #define XGETOPT_H
10 |
11 | #include "embed.h"
12 |
13 | enum {
14 | xargument_no = 0,
15 | xargument_required,
16 | xargument_optional
17 | };
18 |
19 | struct xoption {
20 | char opt;
21 | const char *name;
22 | int has_arg;
23 | int *flag;
24 | int val;
25 | };
26 |
27 | int xgetopt(int argc, const char* argv[], const struct xoption* options, int* optind, const char **optarg);
28 |
29 | #endif
30 |
--------------------------------------------------------------------------------
/src/transport_cache.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014, Vietor Liu
3 | *
4 | * This program is free software; you can redistribute it and/or
5 | * modify it under the terms of the GNU General Public License
6 | * as published by the Free Software Foundation; either version 2
7 | * of the License, or any later version. For full terms that can be
8 | * found in the LICENSE file.
9 | */
10 |
11 | #include "dnsproxy.h"
12 |
13 | static struct {
14 | unsigned int count;
15 | unsigned short index;
16 | unsigned short timeout;
17 | struct rbtree rb_new;
18 | struct list_head list;
19 | } g_cache;
20 |
21 | static int new_search(const void* k, const struct rbnode* r)
22 | {
23 | TRANSPORT_CACHE *right;
24 | right = rbtree_entry(r, TRANSPORT_CACHE, rb_new);
25 | return (int)*(unsigned short*)k - right->new_id;
26 | }
27 |
28 | static int new_compare(const struct rbnode* l, const struct rbnode* r)
29 | {
30 | TRANSPORT_CACHE *left, *right;
31 | left = rbtree_entry(l, TRANSPORT_CACHE, rb_new);
32 | right = rbtree_entry(r, TRANSPORT_CACHE, rb_new);
33 | return (int)left->new_id - right->new_id;
34 | }
35 |
36 | void transport_cache_init(unsigned short timeout)
37 | {
38 | g_cache.count = 0;
39 | g_cache.timeout = timeout;
40 | g_cache.index = (unsigned short)rand();
41 | rbtree_init(&g_cache.rb_new, new_search, new_compare);
42 | list_init(&g_cache.list);
43 | }
44 |
45 | TRANSPORT_CACHE* transport_cache_search(unsigned short new_id)
46 | {
47 | struct rbnode *node = rbtree_search(&g_cache.rb_new, &new_id);
48 | if(node == RBNODE_NULL)
49 | return NULL;
50 | return rbtree_entry(node, TRANSPORT_CACHE, rb_new);
51 | }
52 |
53 | TRANSPORT_CACHE* transport_cache_insert(unsigned short old_id, struct sockaddr_in *address, void *context)
54 | {
55 | TRANSPORT_CACHE *cache = (TRANSPORT_CACHE*)calloc(1, sizeof(TRANSPORT_CACHE));
56 | if(cache == NULL)
57 | return NULL;
58 | cache->context = context;
59 | cache->new_id = ++g_cache.index;
60 | cache->expire = time(NULL) + g_cache.timeout;
61 | cache->old_id = old_id;
62 | memcpy(&cache->source, address, sizeof(struct sockaddr_in));
63 | ++g_cache.count;
64 | list_insert(&g_cache.list, &cache->list);
65 | rbtree_insert(&g_cache.rb_new, &cache->rb_new);
66 | return cache;
67 | }
68 |
69 | void transport_cache_delete(TRANSPORT_CACHE *cache)
70 | {
71 | --g_cache.count;
72 | list_remove(&cache->list);
73 | rbtree_delete(&g_cache.rb_new, &cache->rb_new);
74 | free(cache);
75 | }
76 |
77 | void transport_cache_clean(time_t current)
78 | {
79 | TRANSPORT_CACHE *cache, *tmp;
80 |
81 | if(list_empty(&g_cache.list))
82 | return;
83 | list_for_each_safe(cache, tmp, &g_cache.list, TRANSPORT_CACHE, list) {
84 | if(cache->expire > current)
85 | break;
86 | transport_cache_delete(cache);
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/utils/dnspd:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Startup script for the DNS proxy server
4 | #
5 | # chkconfig: - 49 50
6 | # description: This script starts your DNS proxy server
7 |
8 | . /etc/rc.d/init.d/functions
9 |
10 | OPTIONS="-d -R 8.8.8.8"
11 | HOSTSFILE="/etc/dnspd.hosts"
12 |
13 | if [ -f $HOSTSFILE ]; then
14 | OPTIONS=$OPTIONS" -f "$HOSTSFILE
15 | fi
16 |
17 | name="dnsproxy"
18 | exec="/usr/sbin/$name"
19 | pidfile="/var/run/dnspd/dnspd.pid"
20 | lockfile="/var/lock/subsys/dnspd"
21 |
22 | [ -f $exec ] || exit 0
23 |
24 | RETVAL=0
25 |
26 | case "$1" in
27 | start)
28 | if [ $UID -ne 0 ] ; then
29 | echo "This script must be run as root."
30 | exit 4
31 | fi
32 | echo -n "Starting dnsproxy: "
33 | daemon $exec $OPTIONS
34 | RETVAL=$?
35 | echo
36 | [ $RETVAL -eq 0 ] && touch $lockfile
37 | ;;
38 | stop)
39 | echo -n "Shutting down dnsproxy: "
40 | killproc $name
41 | RETVAL=$?
42 | echo
43 | [ $RETVAL -eq 0 ] && rm -f $lockfile $pidfile
44 | ;;
45 | status)
46 | status $name
47 | RETVAL=$?
48 | ;;
49 | restart|reload|force-reload)
50 | $0 stop
51 | $0 start
52 | RETVAL=$?
53 | ;;
54 | *)
55 | echo "Usage: $0 {start|stop|restart|reload|force-reload|status}"
56 | exit 2
57 | esac
58 |
59 | exit $RETVAL
60 |
--------------------------------------------------------------------------------