make daniel happy
Jan Wagner
17 years ago
0 | GNU GENERAL PUBLIC LICENSE | |
1 | Version 2, June 1991 | |
2 | ||
3 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. | |
4 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
5 | Everyone is permitted to copy and distribute verbatim copies | |
6 | of this license document, but changing it is not allowed. | |
7 | ||
8 | Preamble | |
9 | ||
10 | The licenses for most software are designed to take away your | |
11 | freedom to share and change it. By contrast, the GNU General Public | |
12 | License is intended to guarantee your freedom to share and change free | |
13 | software--to make sure the software is free for all its users. This | |
14 | General Public License applies to most of the Free Software | |
15 | Foundation's software and to any other program whose authors commit to | |
16 | using it. (Some other Free Software Foundation software is covered by | |
17 | the GNU Library General Public License instead.) You can apply it to | |
18 | your programs, too. | |
19 | ||
20 | When we speak of free software, we are referring to freedom, not | |
21 | price. Our General Public Licenses are designed to make sure that you | |
22 | have the freedom to distribute copies of free software (and charge for | |
23 | this service if you wish), that you receive source code or can get it | |
24 | if you want it, that you can change the software or use pieces of it | |
25 | in new free programs; and that you know you can do these things. | |
26 | ||
27 | To protect your rights, we need to make restrictions that forbid | |
28 | anyone to deny you these rights or to ask you to surrender the rights. | |
29 | These restrictions translate to certain responsibilities for you if you | |
30 | distribute copies of the software, or if you modify it. | |
31 | ||
32 | For example, if you distribute copies of such a program, whether | |
33 | gratis or for a fee, you must give the recipients all the rights that | |
34 | you have. You must make sure that they, too, receive or can get the | |
35 | source code. And you must show them these terms so they know their | |
36 | rights. | |
37 | ||
38 | We protect your rights with two steps: (1) copyright the software, and | |
39 | (2) offer you this license which gives you legal permission to copy, | |
40 | distribute and/or modify the software. | |
41 | ||
42 | Also, for each author's protection and ours, we want to make certain | |
43 | that everyone understands that there is no warranty for this free | |
44 | software. If the software is modified by someone else and passed on, we | |
45 | want its recipients to know that what they have is not the original, so | |
46 | that any problems introduced by others will not reflect on the original | |
47 | authors' reputations. | |
48 | ||
49 | Finally, any free program is threatened constantly by software | |
50 | patents. We wish to avoid the danger that redistributors of a free | |
51 | program will individually obtain patent licenses, in effect making the | |
52 | program proprietary. To prevent this, we have made it clear that any | |
53 | patent must be licensed for everyone's free use or not licensed at all. | |
54 | ||
55 | The precise terms and conditions for copying, distribution and | |
56 | modification follow. | |
57 | ||
58 | GNU GENERAL PUBLIC LICENSE | |
59 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |
60 | ||
61 | 0. This License applies to any program or other work which contains | |
62 | a notice placed by the copyright holder saying it may be distributed | |
63 | under the terms of this General Public License. The "Program", below, | |
64 | refers to any such program or work, and a "work based on the Program" | |
65 | means either the Program or any derivative work under copyright law: | |
66 | that is to say, a work containing the Program or a portion of it, | |
67 | either verbatim or with modifications and/or translated into another | |
68 | language. (Hereinafter, translation is included without limitation in | |
69 | the term "modification".) Each licensee is addressed as "you". | |
70 | ||
71 | Activities other than copying, distribution and modification are not | |
72 | covered by this License; they are outside its scope. The act of | |
73 | running the Program is not restricted, and the output from the Program | |
74 | is covered only if its contents constitute a work based on the | |
75 | Program (independent of having been made by running the Program). | |
76 | Whether that is true depends on what the Program does. | |
77 | ||
78 | 1. You may copy and distribute verbatim copies of the Program's | |
79 | source code as you receive it, in any medium, provided that you | |
80 | conspicuously and appropriately publish on each copy an appropriate | |
81 | copyright notice and disclaimer of warranty; keep intact all the | |
82 | notices that refer to this License and to the absence of any warranty; | |
83 | and give any other recipients of the Program a copy of this License | |
84 | along with the Program. | |
85 | ||
86 | You may charge a fee for the physical act of transferring a copy, and | |
87 | you may at your option offer warranty protection in exchange for a fee. | |
88 | ||
89 | 2. You may modify your copy or copies of the Program or any portion | |
90 | of it, thus forming a work based on the Program, and copy and | |
91 | distribute such modifications or work under the terms of Section 1 | |
92 | above, provided that you also meet all of these conditions: | |
93 | ||
94 | a) You must cause the modified files to carry prominent notices | |
95 | stating that you changed the files and the date of any change. | |
96 | ||
97 | b) You must cause any work that you distribute or publish, that in | |
98 | whole or in part contains or is derived from the Program or any | |
99 | part thereof, to be licensed as a whole at no charge to all third | |
100 | parties under the terms of this License. | |
101 | ||
102 | c) If the modified program normally reads commands interactively | |
103 | when run, you must cause it, when started running for such | |
104 | interactive use in the most ordinary way, to print or display an | |
105 | announcement including an appropriate copyright notice and a | |
106 | notice that there is no warranty (or else, saying that you provide | |
107 | a warranty) and that users may redistribute the program under | |
108 | these conditions, and telling the user how to view a copy of this | |
109 | License. (Exception: if the Program itself is interactive but | |
110 | does not normally print such an announcement, your work based on | |
111 | the Program is not required to print an announcement.) | |
112 | ||
113 | These requirements apply to the modified work as a whole. If | |
114 | identifiable sections of that work are not derived from the Program, | |
115 | and can be reasonably considered independent and separate works in | |
116 | themselves, then this License, and its terms, do not apply to those | |
117 | sections when you distribute them as separate works. But when you | |
118 | distribute the same sections as part of a whole which is a work based | |
119 | on the Program, the distribution of the whole must be on the terms of | |
120 | this License, whose permissions for other licensees extend to the | |
121 | entire whole, and thus to each and every part regardless of who wrote it. | |
122 | ||
123 | Thus, it is not the intent of this section to claim rights or contest | |
124 | your rights to work written entirely by you; rather, the intent is to | |
125 | exercise the right to control the distribution of derivative or | |
126 | collective works based on the Program. | |
127 | ||
128 | In addition, mere aggregation of another work not based on the Program | |
129 | with the Program (or with a work based on the Program) on a volume of | |
130 | a storage or distribution medium does not bring the other work under | |
131 | the scope of this License. | |
132 | ||
133 | 3. You may copy and distribute the Program (or a work based on it, | |
134 | under Section 2) in object code or executable form under the terms of | |
135 | Sections 1 and 2 above provided that you also do one of the following: | |
136 | ||
137 | a) Accompany it with the complete corresponding machine-readable | |
138 | source code, which must be distributed under the terms of Sections | |
139 | 1 and 2 above on a medium customarily used for software interchange; or, | |
140 | ||
141 | b) Accompany it with a written offer, valid for at least three | |
142 | years, to give any third party, for a charge no more than your | |
143 | cost of physically performing source distribution, a complete | |
144 | machine-readable copy of the corresponding source code, to be | |
145 | distributed under the terms of Sections 1 and 2 above on a medium | |
146 | customarily used for software interchange; or, | |
147 | ||
148 | c) Accompany it with the information you received as to the offer | |
149 | to distribute corresponding source code. (This alternative is | |
150 | allowed only for noncommercial distribution and only if you | |
151 | received the program in object code or executable form with such | |
152 | an offer, in accord with Subsection b above.) | |
153 | ||
154 | The source code for a work means the preferred form of the work for | |
155 | making modifications to it. For an executable work, complete source | |
156 | code means all the source code for all modules it contains, plus any | |
157 | associated interface definition files, plus the scripts used to | |
158 | control compilation and installation of the executable. However, as a | |
159 | special exception, the source code distributed need not include | |
160 | anything that is normally distributed (in either source or binary | |
161 | form) with the major components (compiler, kernel, and so on) of the | |
162 | operating system on which the executable runs, unless that component | |
163 | itself accompanies the executable. | |
164 | ||
165 | If distribution of executable or object code is made by offering | |
166 | access to copy from a designated place, then offering equivalent | |
167 | access to copy the source code from the same place counts as | |
168 | distribution of the source code, even though third parties are not | |
169 | compelled to copy the source along with the object code. | |
170 | ||
171 | 4. You may not copy, modify, sublicense, or distribute the Program | |
172 | except as expressly provided under this License. Any attempt | |
173 | otherwise to copy, modify, sublicense or distribute the Program is | |
174 | void, and will automatically terminate your rights under this License. | |
175 | However, parties who have received copies, or rights, from you under | |
176 | this License will not have their licenses terminated so long as such | |
177 | parties remain in full compliance. | |
178 | ||
179 | 5. You are not required to accept this License, since you have not | |
180 | signed it. However, nothing else grants you permission to modify or | |
181 | distribute the Program or its derivative works. These actions are | |
182 | prohibited by law if you do not accept this License. Therefore, by | |
183 | modifying or distributing the Program (or any work based on the | |
184 | Program), you indicate your acceptance of this License to do so, and | |
185 | all its terms and conditions for copying, distributing or modifying | |
186 | the Program or works based on it. | |
187 | ||
188 | 6. Each time you redistribute the Program (or any work based on the | |
189 | Program), the recipient automatically receives a license from the | |
190 | original licensor to copy, distribute or modify the Program subject to | |
191 | these terms and conditions. You may not impose any further | |
192 | restrictions on the recipients' exercise of the rights granted herein. | |
193 | You are not responsible for enforcing compliance by third parties to | |
194 | this License. | |
195 | ||
196 | 7. If, as a consequence of a court judgment or allegation of patent | |
197 | infringement or for any other reason (not limited to patent issues), | |
198 | conditions are imposed on you (whether by court order, agreement or | |
199 | otherwise) that contradict the conditions of this License, they do not | |
200 | excuse you from the conditions of this License. If you cannot | |
201 | distribute so as to satisfy simultaneously your obligations under this | |
202 | License and any other pertinent obligations, then as a consequence you | |
203 | may not distribute the Program at all. For example, if a patent | |
204 | license would not permit royalty-free redistribution of the Program by | |
205 | all those who receive copies directly or indirectly through you, then | |
206 | the only way you could satisfy both it and this License would be to | |
207 | refrain entirely from distribution of the Program. | |
208 | ||
209 | If any portion of this section is held invalid or unenforceable under | |
210 | any particular circumstance, the balance of the section is intended to | |
211 | apply and the section as a whole is intended to apply in other | |
212 | circumstances. | |
213 | ||
214 | It is not the purpose of this section to induce you to infringe any | |
215 | patents or other property right claims or to contest validity of any | |
216 | such claims; this section has the sole purpose of protecting the | |
217 | integrity of the free software distribution system, which is | |
218 | implemented by public license practices. Many people have made | |
219 | generous contributions to the wide range of software distributed | |
220 | through that system in reliance on consistent application of that | |
221 | system; it is up to the author/donor to decide if he or she is willing | |
222 | to distribute software through any other system and a licensee cannot | |
223 | impose that choice. | |
224 | ||
225 | This section is intended to make thoroughly clear what is believed to | |
226 | be a consequence of the rest of this License. | |
227 | ||
228 | 8. If the distribution and/or use of the Program is restricted in | |
229 | certain countries either by patents or by copyrighted interfaces, the | |
230 | original copyright holder who places the Program under this License | |
231 | may add an explicit geographical distribution limitation excluding | |
232 | those countries, so that distribution is permitted only in or among | |
233 | countries not thus excluded. In such case, this License incorporates | |
234 | the limitation as if written in the body of this License. | |
235 | ||
236 | 9. The Free Software Foundation may publish revised and/or new versions | |
237 | of the General Public License from time to time. Such new versions will | |
238 | be similar in spirit to the present version, but may differ in detail to | |
239 | address new problems or concerns. | |
240 | ||
241 | Each version is given a distinguishing version number. If the Program | |
242 | specifies a version number of this License which applies to it and "any | |
243 | later version", you have the option of following the terms and conditions | |
244 | either of that version or of any later version published by the Free | |
245 | Software Foundation. If the Program does not specify a version number of | |
246 | this License, you may choose any version ever published by the Free Software | |
247 | Foundation. | |
248 | ||
249 | 10. If you wish to incorporate parts of the Program into other free | |
250 | programs whose distribution conditions are different, write to the author | |
251 | to ask for permission. For software which is copyrighted by the Free | |
252 | Software Foundation, write to the Free Software Foundation; we sometimes | |
253 | make exceptions for this. Our decision will be guided by the two goals | |
254 | of preserving the free status of all derivatives of our free software and | |
255 | of promoting the sharing and reuse of software generally. | |
256 | ||
257 | NO WARRANTY | |
258 | ||
259 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | |
260 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN | |
261 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | |
262 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED | |
263 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
264 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS | |
265 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE | |
266 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, | |
267 | REPAIR OR CORRECTION. | |
268 | ||
269 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | |
270 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | |
271 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | |
272 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING | |
273 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED | |
274 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY | |
275 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER | |
276 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE | |
277 | POSSIBILITY OF SUCH DAMAGES. | |
278 | ||
279 | END OF TERMS AND CONDITIONS | |
280 |
0 | DNS FLood Detector 1.10 | |
1 | Dennis Opacki | |
2 | dopacki@adotout.com | |
3 | ||
4 | ||
5 | What is DNS Flood Detector? | |
6 | ||
7 | DNS Flood Detector was developed to detect abusive usage levels on high | |
8 | traffic nameservers and to enable quick response to the use of one's | |
9 | nameserver to facilitate spam. DNS Flood Detector is distributed under the | |
10 | Gnu Public License (see included LICENSE file for details). | |
11 | ||
12 | How does it work? | |
13 | ||
14 | DNS Flood Detector uses libpcap (in non-promiscuous mode) to monitor | |
15 | incoming dns queries to a nameserver. The tool may be run in one of two | |
16 | modes, either daemon mode or "bindsnap" mode. In daemon mode, the tool | |
17 | will alarm via syslog. In bindsnap mode, the user is able to get | |
18 | near-real-time stats on usage to aid in more detailed troubleshooting. | |
19 | ||
20 | How do I build it? | |
21 | ||
22 | Execute ./configure.pl to select the appropriate make target. Then simply | |
23 | type "make". | |
24 | ||
25 | Why was it written? | |
26 | ||
27 | I wrote DNS Flood Detector because the fifty or so public recursive | |
28 | nameservers I am responsible for were being abused by both customers and | |
29 | non-customers. DNS Flood Detector allows for prompt action when anomalous | |
30 | conditions are detected. | |
31 | ||
32 | What do I need to use it? | |
33 | ||
34 | You need libpcap and a little bit of patience. | |
35 | ||
36 | What platforms does it work on? | |
37 | ||
38 | Linux, BSDI, FreeBSD, Mac OSX, Solaris | |
39 | ||
40 | Will it run under Windows {95,98,NT,2000,XP}? | |
41 | ||
42 | Maybe. I haven't tried. If it doesn't, feel free to submit a fix. | |
43 | ||
44 | What does it look like? | |
45 | ||
46 | Usage: ./dns_flood_detector [OPTION] | |
47 | ||
48 | -i IFNAME specify interface to listen on | |
49 | -t N alarm at >N queries per second | |
50 | -a N reset alarm after N seconds | |
51 | -w N calculate stats every N seconds | |
52 | -x N create N buckets | |
53 | -m N mark total query rate every N seconds | |
54 | -b run in foreground in bindsnap mode | |
55 | -d run in background in daemon mode | |
56 | -v verbose output - use again for more verbosity | |
57 | -h display this usage information | |
58 | ||
59 | Sample Output: | |
60 | ||
61 | dopacki:~$ sudo ./dns_flood_detector -v -v -b -t10 | |
62 | [15:14:56] source [192.168.1.45] - 0 qps tcp : 24 qps udp [8 qps A] [16 | |
63 | qps PTR] | |
64 | [15:14:56] source [10.0.24.2] - 0 qps tcp : 15 qps udp [15 qps A] | |
65 | [15:15:06] source [192.168.1.45] - 0 qps tcp : 24 qps udp [8 qps A] [16 | |
66 | qps PTR] | |
67 | [15:15:06] source [10.0.24.2] - 0 qps tcp : 15 qps udp [14 qps A] | |
68 | [15:15:16] source [192.168.1.45] - 0 qps tcp : 23 qps udp [7 qps A] [15 | |
69 | qps PTR] | |
70 | ||
71 | What if I have questions? | |
72 | ||
73 | You can e-mail me at dopacki@adotout.com |
0 | #!/usr/bin/perl | |
1 | ||
2 | use strict; | |
3 | ||
4 | my $os = shift; | |
5 | ||
6 | # get target listings | |
7 | opendir(MAKE_TARGETS,'./makefiles'); | |
8 | my @targets = grep { /Makefile/ && -f './makefiles/'.$_ && s/^Makefile-// } readdir(MAKE_TARGETS); | |
9 | closedir(MAKE_TARGETS); | |
10 | ||
11 | # display usage | |
12 | unless ($os && grep{/$os/}@targets) {print<<EOF;exit(0)} | |
13 | usage: $0 {@targets} | |
14 | EOF | |
15 | ||
16 | # link appropriate target | |
17 | symlink './makefiles/Makefile-'.$os, 'Makefile'; | |
18 | print "type make.\n"; |
0 | /******************************************************************************** | |
1 | ||
2 | Program: dns_flood_detector.c | |
3 | Author: Dennis Opacki <dopacki@adotout.com> | |
4 | Date: Tue Mar 18 16:46:53 EST 2003 | |
5 | Purpose: Monitor DNS servers for abusive usage levels | |
6 | and alarm to syslog | |
7 | ||
8 | compile with: | |
9 | gcc -o dns_flood_detector -lpcap -lpthread -lm dns_flood_detector.c | |
10 | ||
11 | command-line options: | |
12 | ||
13 | -i ifname specify interface to listen on (default lets pcap pick) | |
14 | -t n alarm when more than n queries per second are observed | |
15 | (default 40) | |
16 | -a n wait for n seconds before alarming again on same source | |
17 | (default 90) | |
18 | -w n calculate statistics every n seconds | |
19 | (default 10) | |
20 | -x n use n buckets | |
21 | (default 50) | |
22 | -m n mark overall query rate every n seconds | |
23 | (default disabled) | |
24 | -b run in foreground in "bindsnap" mode | |
25 | -d run in background in "daemon" mode | |
26 | -v detailed information (use twice for more detail) | |
27 | -h usage info | |
28 | ||
29 | Copyright (C) 2003 Dennis Opacki | |
30 | ||
31 | This program is free software; you can redistribute it and/or modify | |
32 | it under the terms of the GNU General Public License as published by | |
33 | the Free Software Foundation; either version 2 of the License, or | |
34 | (at your option) any later version. | |
35 | ||
36 | This program is distributed in the hope that it will be useful, | |
37 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
38 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
39 | GNU General Public License for more details. | |
40 | ||
41 | You should have received a copy of the GNU General Public License | |
42 | along with this program; if not, write to the Free Software | |
43 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
44 | ||
45 | --- new in v1.05 --- | |
46 | 8/18/2003 - FreeBSD target - Jim Westfall <jwestfall@surrealistic.net> | |
47 | 8/18/2003 - Moved to getopt(3) for compatibility <dopacki@adotout.com> | |
48 | 8/19/2003 - Added OSX/BSDI make targets - <dopacki@adotout.com> | |
49 | Added ability to specify inteface - <dopacki@adotout.com> | |
50 | ||
51 | --- new in v1.06 --- | |
52 | 8/20/2003 - Added Solaris9 make target - <dopacki@adotout.com> | |
53 | 8/26/2003 - Fixed tcp qdcount bug - <dopacki@adotout.com> | |
54 | ||
55 | --- new in v1.07 --- | |
56 | 8/27/2003 - Fixed alarm reset bug - <dopacki@adotout.com> | |
57 | 8/28/2003 - Added malloc_fail function - <dopacki@adotout.com> | |
58 | 8/28/2003 - Added mutex thread locking - <dopacki@adotout.com> | |
59 | 8/30/2003 - Fixed wierd qtype segfault - <jwestfall@surrealistic.net> | |
60 | <dopacki@adotout.com> | |
61 | ||
62 | --- new in v1.08 --- | |
63 | 9/02/2003 - Added -v -v output in daemon mode - <dopacki@adotout.com> | |
64 | ||
65 | --- new in v1.09 --- | |
66 | 10/19/2003 - Added stdout flushing to bindsnap mode - <dopacki@adotout.com> | |
67 | 10/19/2003 - Changed logging priority to LOG_NOTICE - <dopacki@adotout.com> | |
68 | 10/19/2003 - Fixed low traffic verbose logging bugs - <dopacki@adotout.com> | |
69 | ||
70 | --- new in v1.10 --- | |
71 | 10/22/2003 - Added 'mark status' option via '-m' - <dopacki@adotout.com> | |
72 | 10/23/2003 - Code cleanup in verbose syslogging - <dopacki@adotout.com> | |
73 | ||
74 | ********************************************************************************/ | |
75 | ||
76 | #include <pcap.h> | |
77 | #include <stdio.h> | |
78 | #include <stdlib.h> | |
79 | #include <fcntl.h> | |
80 | #include <errno.h> | |
81 | #include <netinet/in_systm.h> | |
82 | #include <netinet/in.h> | |
83 | #include <netinet/ip.h> | |
84 | #include <netinet/tcp.h> | |
85 | #include <netinet/udp.h> | |
86 | #ifdef __bsdi__ | |
87 | #include <net/if_ethernet.h> | |
88 | #else | |
89 | #ifdef __sun__ | |
90 | #include <sys/ethernet.h> | |
91 | #else | |
92 | #include <net/ethernet.h> | |
93 | #endif | |
94 | #endif | |
95 | #include <pthread.h> | |
96 | #include <unistd.h> | |
97 | #include <time.h> | |
98 | #include <math.h> | |
99 | #include <signal.h> | |
100 | #include <syslog.h> | |
101 | #include "dns_flood_detector.h" | |
102 | ||
103 | // global variables and their defaults | |
104 | pthread_mutex_t stats_lock; | |
105 | struct bucket **bb; | |
106 | int option_t = 60; | |
107 | int option_a = 90; | |
108 | int option_w = 10; | |
109 | int option_x = 50; | |
110 | int option_m = 0; | |
111 | int option_b = 0; | |
112 | int option_d = 0; | |
113 | int option_v = 0; | |
114 | int option_h = 0; | |
115 | int totals = 0; | |
116 | char VERSION[] = "1.10"; | |
117 | ||
118 | // this is our statistics thread | |
119 | void *run_stats () { | |
120 | while (1) { | |
121 | ||
122 | // check statistical stuff | |
123 | pthread_mutex_lock(&stats_lock); | |
124 | calculate_averages(); | |
125 | pthread_mutex_unlock(&stats_lock); | |
126 | ||
127 | sleep (option_w); | |
128 | } | |
129 | } | |
130 | ||
131 | // calculate the running average within each bucket | |
132 | int calculate_averages() { | |
133 | u_int i,j,delta,cursize,newsize,qps; | |
134 | char st_time[10]; | |
135 | time_t now = time(0); | |
136 | u_int types[] = {1,2,5,6,12,15,252,0}; | |
137 | u_char *type; | |
138 | u_char *target; | |
139 | char *names[] = {"A","NS","CNAME","SOA","PTR","MX","AXFR",""}; | |
140 | struct tm *raw_time = localtime(&now); | |
141 | snprintf(st_time, 9, "%02d:%02d:%02d",raw_time->tm_hour,raw_time->tm_min,raw_time->tm_sec); | |
142 | ||
143 | for (i=0; i<option_x; i++) { | |
144 | ||
145 | // only process valid buckets | |
146 | if ( bb[i]->ip_addr != NULL ) { | |
147 | delta = now - bb[i]->first_packet; | |
148 | ||
149 | // let's try to avoid a divide-by-zero, shall we? | |
150 | if (delta > 1 ) { | |
151 | ||
152 | // round our average and save it in the bucket | |
153 | bb[i]->qps = (int)ceil( (float)((((float)bb[i]->tcp_count) + bb[i]->udp_count) / delta)); | |
154 | ||
155 | // handle threshold crossing | |
156 | if ( bb[i]->qps > option_t ) { | |
157 | ||
158 | ||
159 | // display detail to either syslog or stdout | |
160 | if ( option_b ) { | |
161 | if ( ! option_v ) { | |
162 | printf("[%s] source [%s] - %d qps\n",st_time,bb[i]->ip_addr,bb[i]->qps); | |
163 | fflush(stdout); | |
164 | } | |
165 | else { | |
166 | printf("[%s] source [%s] - %d qps tcp : %d qps udp ",st_time,bb[i]->ip_addr, | |
167 | (int)ceil( (float)(bb[i]->tcp_count/delta)), | |
168 | (int)ceil( (float)(bb[i]->udp_count/delta)) | |
169 | ); | |
170 | if ( option_v >1 ) { | |
171 | for (j=0;types[j];j++) { | |
172 | if ((int)ceil((float)(bb[i]->qstats[types[j]]/delta))){ | |
173 | printf("[%d qps %s] ",(int)ceil((float)(bb[i]->qstats[types[j]]/delta)),names[j]); | |
174 | } | |
175 | } | |
176 | } | |
177 | printf("\n"); | |
178 | fflush(stdout); | |
179 | } | |
180 | } | |
181 | else { | |
182 | // if running in background, use alarm reset timer | |
183 | if ((now-bb[i]->alarm_set)>option_a) { | |
184 | ||
185 | // display appropriate level of detail via syslog | |
186 | if ( ! option_v ) { | |
187 | syslog(LOG_NOTICE,"source [%s] - %d qps\n",bb[i]->ip_addr,bb[i]->qps); | |
188 | } | |
189 | else if (option_v > 1) { | |
190 | target = (char *)malloc(sizeof(char)*MAXSYSLOG); | |
191 | newsize = MAXSYSLOG; | |
192 | cursize = snprintf(target,newsize,"source [%s] - %d tcp qps : %d udp qps ",bb[i]->ip_addr, | |
193 | (int)ceil( (float)(bb[i]->tcp_count/delta)), | |
194 | (int)ceil( (float)(bb[i]->udp_count/delta)) | |
195 | ); | |
196 | newsize-=cursize; | |
197 | ||
198 | for (j=0;types[j];j++ ) { | |
199 | qps = (u_int)ceil((float)(bb[i]->qstats[types[j]]/delta)); | |
200 | if ( ( qps > 0) && ( newsize > 1 ) ) { | |
201 | cursize = snprintf(target+(MAXSYSLOG-newsize),newsize,"[%d qps %s] ",qps,names[j]); | |
202 | newsize-=cursize; | |
203 | } | |
204 | } | |
205 | if (newsize <= 0 ) { | |
206 | target[MAXSYSLOG-1]='\0'; | |
207 | } | |
208 | syslog(LOG_NOTICE,"%s",target); | |
209 | free(target); | |
210 | } | |
211 | else { | |
212 | syslog(LOG_NOTICE,"source [%s] - %d tcp qps - %d udp qps\n",bb[i]->ip_addr, | |
213 | (int)ceil( (float)(bb[i]->tcp_count/delta)), | |
214 | (int)ceil( (float)(bb[i]->udp_count/delta)) | |
215 | ); | |
216 | } | |
217 | ||
218 | // reset alarm | |
219 | bb[i]->alarm_set = now; | |
220 | } | |
221 | } | |
222 | } | |
223 | } | |
224 | } | |
225 | } | |
226 | ||
227 | // 'mark stats' if required and it is time | |
228 | delta = now - bb[totals]->first_packet; | |
229 | if ( (option_m > 0)&&(delta > 1)&&(delta >= option_m) ) { | |
230 | ||
231 | // handle bindsnap mode | |
232 | if (option_b) { | |
233 | printf("[%s] totals - %d qps tcp : %d qps udp ",st_time,(int)ceil( (float)(bb[totals]->tcp_count/delta)),(int)ceil( (float)(bb[totals]->udp_count/delta))); | |
234 | if (option_v) { | |
235 | for (j=0;types[j];j++) { | |
236 | qps = (u_int)ceil((float)(bb[totals]->qstats[types[j]]/delta)); | |
237 | if (qps){ | |
238 | printf("[%d qps %s] ",qps,names[j]); | |
239 | } | |
240 | } | |
241 | } | |
242 | printf("\n"); | |
243 | fflush(stdout); | |
244 | } | |
245 | else { | |
246 | // agonizing high verbosity code | |
247 | if (option_v) { | |
248 | target = (char *)malloc(sizeof(char)*MAXSYSLOG); | |
249 | newsize = MAXSYSLOG; | |
250 | cursize = snprintf(target,newsize,"[totals] - %d tcp qps : %d udp qps ", | |
251 | (int)ceil( (float)(bb[totals]->tcp_count/delta)), | |
252 | (int)ceil( (float)(bb[totals]->udp_count/delta)) | |
253 | ); | |
254 | newsize-=cursize; | |
255 | ||
256 | for (j=0;types[j];j++ ) { | |
257 | qps = (u_int)ceil((float)(bb[totals]->qstats[types[j]]/delta)); | |
258 | if ( ( qps > 0) && ( newsize > 1 ) ) { | |
259 | cursize = snprintf(target+(MAXSYSLOG-newsize),newsize,"[%d qps %s] ",qps,names[j]); | |
260 | newsize-=cursize; | |
261 | } | |
262 | } | |
263 | if (newsize <= 0 ) { | |
264 | target[MAXSYSLOG-1]='\0'; | |
265 | } | |
266 | syslog(LOG_NOTICE,"%s",target); | |
267 | free(target); | |
268 | } | |
269 | else { | |
270 | syslog(LOG_NOTICE,"[totals] - %d tcp qps : %d udp qps\n", | |
271 | (int)ceil( (float)(bb[totals]->tcp_count/delta)), | |
272 | (int)ceil( (float)(bb[totals]->udp_count/delta)) | |
273 | ); | |
274 | } | |
275 | } | |
276 | scour_bucket(totals); | |
277 | } | |
278 | ||
279 | return 1; | |
280 | } | |
281 | ||
282 | // purge and initialize all buckets | |
283 | void init_buckets() { | |
284 | u_int i; | |
285 | ||
286 | // create bucket brigade (final bucket is for totals) | |
287 | pthread_mutex_lock(&stats_lock); | |
288 | if ( ( bb = malloc( sizeof(struct bucket *) * (option_x+1)) ) == NULL ) malloc_fail("bb", sizeof(struct bucket *) * (option_x+1)); | |
289 | for (i=0; i <=option_x; i++ ) { | |
290 | if ( ( bb[i] = (struct bucket *)malloc( sizeof(struct bucket) ) ) == NULL) malloc_fail("bb[i]", sizeof(struct bucket) ); | |
291 | bb[i]->ip_addr=NULL; | |
292 | scour_bucket(i); | |
293 | } | |
294 | pthread_mutex_unlock(&stats_lock); | |
295 | } | |
296 | ||
297 | // clean out a bucket while avoiding obvious memory leak | |
298 | int scour_bucket( int i ) { | |
299 | int j; | |
300 | ||
301 | if ( bb[i]->ip_addr != NULL ) { | |
302 | free ( bb[i]->ip_addr ); | |
303 | } | |
304 | bb[i]->ip_addr=NULL; | |
305 | bb[i]->tcp_count=0; | |
306 | bb[i]->udp_count=0; | |
307 | bb[i]->qps=0; | |
308 | bb[i]->first_packet=time(0); | |
309 | bb[i]->last_packet=(time_t)0; | |
310 | bb[i]->alarm_set=(time_t)0; | |
311 | ||
312 | for (j=0;j<256;j++) { | |
313 | bb[i]->qstats[j]=0; | |
314 | } | |
315 | return 1; | |
316 | } | |
317 | ||
318 | // add a packet to a bucket | |
319 | int add_to_bucket ( char * ip_src, int ip_proto, int num_queries, u_int8_t qtype) { | |
320 | int bucket = 0; | |
321 | ||
322 | // get the bucket to put packet in | |
323 | pthread_mutex_lock(&stats_lock); | |
324 | bucket = find_bucket(ip_src); | |
325 | ||
326 | // set bucket fields | |
327 | bb[bucket]->last_packet = time(0); | |
328 | if (ip_proto == 6 ) { | |
329 | bb[bucket]->tcp_count+=num_queries; | |
330 | bb[totals]->tcp_count+=num_queries; | |
331 | } | |
332 | else { | |
333 | bb[bucket]->udp_count+=num_queries; | |
334 | bb[totals]->udp_count+=num_queries; | |
335 | } | |
336 | ||
337 | bb[bucket]->qstats[qtype]+=num_queries; | |
338 | bb[totals]->qstats[qtype]+=num_queries; | |
339 | pthread_mutex_unlock(&stats_lock); | |
340 | ||
341 | return 1; | |
342 | } | |
343 | ||
344 | // figure out where to put this packet | |
345 | int find_bucket(char *ip_src) { | |
346 | int i, bucket=0; | |
347 | time_t oldest=0; | |
348 | ||
349 | // look for an existing bucket for this IP | |
350 | for (i=0; i< option_x; i++ ){ | |
351 | // ip field of bucket is not null and seems to match the ip we are checking | |
352 | if ((bb[i]->ip_addr != NULL)&&(strncmp(bb[i]->ip_addr, ip_src, strlen(bb[i]->ip_addr))==0)) { | |
353 | return i; | |
354 | } | |
355 | } | |
356 | ||
357 | // look for unused buckets | |
358 | for (i=0; i< option_x; i++ ) { | |
359 | ||
360 | // found an unused one - clean it, init it, and return it | |
361 | if ( bb[i]->ip_addr == NULL ) { | |
362 | scour_bucket(i); | |
363 | if ( ( bb[i]->ip_addr = (char *)strdup(ip_src) ) == NULL) malloc_fail("bb[i]->ip_addr", strlen(ip_src) ); | |
364 | return i; | |
365 | } | |
366 | ||
367 | // find the most stagnant bucket in case we need it | |
368 | // avoids another loop through the buckets | |
369 | if ( ( bb[i]->last_packet != 0 ) && ((oldest==0)||( bb[i]->last_packet < oldest))) { | |
370 | oldest = bb[i]->last_packet; | |
371 | bucket = i; | |
372 | } | |
373 | } | |
374 | ||
375 | // use the most stagnant bucket since all are in use | |
376 | // clean it, init it, and return it | |
377 | scour_bucket(bucket); | |
378 | if ( ( bb[bucket]->ip_addr = (char *)strdup(ip_src) ) == NULL) malloc_fail("bb[bucket]->ip_addr", strlen(ip_src) ); | |
379 | ||
380 | return bucket; | |
381 | } | |
382 | ||
383 | // handle all packets we throw at it | |
384 | void handle_IP(u_char *args, const struct pcap_pkthdr* pkthdr,const u_char* packet){ | |
385 | const struct ip* ip; | |
386 | const struct my_dns *dns; | |
387 | const struct tcphdr *tcp; | |
388 | const struct udphdr *udp; | |
389 | u_int length = pkthdr->len; | |
390 | u_int caplen = pkthdr->caplen; | |
391 | u_int hlen,off,version; | |
392 | unsigned char dname[NS_MAXDNAME]=""; | |
393 | char *ip_src; | |
394 | unsigned char *data; | |
395 | u_int i,len,dpos; | |
396 | u_int8_t qtype,qclass,tlen; | |
397 | ||
398 | // skip the ethernet header | |
399 | length -= sizeof(struct ether_header); | |
400 | ||
401 | // make sure packet is a valid length | |
402 | if (length < sizeof(struct ip)) { | |
403 | return; | |
404 | } | |
405 | ||
406 | // snap off the ip portion | |
407 | ip = (struct ip*)(packet + sizeof(struct ether_header)); | |
408 | ||
409 | // get utility params for sanity checking | |
410 | len = ntohs(ip->ip_len); | |
411 | hlen = ip->ip_hl; | |
412 | version = ip->ip_v; | |
413 | ||
414 | // let's not do ipv6 just yet | |
415 | if(version != 4) { | |
416 | return; | |
417 | } | |
418 | ||
419 | // make sure we have a sane header length | |
420 | if(hlen < 5 ) { | |
421 | return; | |
422 | } | |
423 | ||
424 | // do we have the everything we are supposed to? | |
425 | if(length < len) { | |
426 | return; | |
427 | } | |
428 | ||
429 | // make sure we are only processing the first fragment | |
430 | off = ntohs(ip->ip_off); | |
431 | if((off & 0x1fff) == 0 ) { | |
432 | ||
433 | // get the source ip as a string (probably more efficient to use decimal) | |
434 | ip_src = (char *)inet_ntoa(ip->ip_src); | |
435 | ||
436 | // process udp packets | |
437 | if ( ip->ip_p == 17 ) { | |
438 | udp = (struct udphdr *) ( (char *) packet + sizeof(struct ether_header)+ sizeof (struct ip) ); | |
439 | ||
440 | // try to make sure it is safe to cast packet into dns structure | |
441 | if ( (sizeof(struct my_dns)+sizeof(struct ether_header)+sizeof(struct ip)+sizeof(struct udphdr)) >= caplen ) { | |
442 | return; | |
443 | } | |
444 | else { | |
445 | // populate dns header | |
446 | dns = (struct my_dns *) ( (char *) packet + sizeof(struct ether_header) + sizeof (struct ip) + sizeof (struct udphdr) ); | |
447 | data = (char *) packet +sizeof(struct ether_header) + sizeof (struct ip) + sizeof (struct udphdr) + sizeof(struct my_dns); | |
448 | } | |
449 | } | |
450 | ||
451 | // process tcp packets | |
452 | else if ( ip->ip_p == 6 ) { | |
453 | tcp = (struct tcphdr *) ( (char *) packet + sizeof(struct ether_header)+ sizeof (struct ip) ); | |
454 | ||
455 | // ignore packets without push flag set | |
456 | if (! tcp->th_flags & TH_PUSH) return; | |
457 | ||
458 | // try to make sure it is safe to cast packet into dns structure | |
459 | if ( (sizeof(struct my_dns)+sizeof(struct ether_header)+sizeof(struct ip)+(tcp->th_off * sizeof(u_int32_t))) >= caplen ) { | |
460 | return; | |
461 | } | |
462 | else { | |
463 | // populate dns header | |
464 | dns = (struct my_dns *) ( (char *) packet + sizeof(struct ether_header)+ sizeof (struct ip) + (tcp->th_off * sizeof(u_int32_t))); | |
465 | data = (char *) packet + sizeof(struct ether_header) + sizeof (struct ip) + (tcp->th_off * sizeof(u_int32_t)) + sizeof(struct my_dns); | |
466 | } | |
467 | } | |
468 | ||
469 | // hmm.. not tcp, not udp.. move on. | |
470 | else { | |
471 | return; | |
472 | } | |
473 | ||
474 | // we only want queries, not responses | |
475 | if ( dns->dns_flags1 & 0x80 ) { | |
476 | return; | |
477 | } | |
478 | ||
479 | // ignore seemingly bogus queries with multiple flags set | |
480 | if ((ntohs(dns->dns_qdcount)>0)+(ntohs(dns->dns_ancount)>0)+(ntohs(dns->dns_nscount)>0)+(ntohs(dns->dns_arcount)>0)>1 ) { | |
481 | return; | |
482 | } | |
483 | ||
484 | // get the domain name and query type | |
485 | tlen=dpos=0; | |
486 | for (;(*data)&&((void *)data<((void *)packet+caplen-1)); data++) { | |
487 | if (!tlen) tlen=*data; | |
488 | for (;(tlen&&((void *)data<((void *)packet+caplen-1)));tlen--){ | |
489 | data++; | |
490 | if (dpos<NS_MAXDNAME) dname[dpos++] = *data; | |
491 | } | |
492 | if (dpos<NS_MAXDNAME) dname[dpos++] = '.'; | |
493 | } | |
494 | dname[dpos]='\0'; | |
495 | ||
496 | // be careful not to walk past the end of the captured data | |
497 | if ( (void *)data < ((void *)packet+caplen-3) ) { | |
498 | data+=2; | |
499 | qtype = *data; | |
500 | } | |
501 | else { | |
502 | return; | |
503 | } | |
504 | ||
505 | // add packet to bucket array | |
506 | if (ntohs(dns->dns_qdcount)&&qtype) { | |
507 | add_to_bucket( ip_src, ip->ip_p, 1, qtype ); | |
508 | } | |
509 | } | |
510 | return; | |
511 | } | |
512 | ||
513 | // main logic | |
514 | // some pcap code borrowed from http://www.cet.nau.edu/~mc8/Socket/Tutorials/section1.html | |
515 | int main(int argc,char **argv){ | |
516 | char *dev = NULL; | |
517 | pthread_t thread; | |
518 | char errbuf[PCAP_ERRBUF_SIZE]; | |
519 | pcap_t* descr; | |
520 | struct bpf_program fp; /* hold compiled program */ | |
521 | bpf_u_int32 maskp=0; /* subnet mask */ | |
522 | bpf_u_int32 netp=0; /* ip */ | |
523 | char *filter = NULL; | |
524 | char *dst_addr = NULL; | |
525 | char *dst_mask = NULL; | |
526 | struct sigaction sa; | |
527 | struct in_addr addr; | |
528 | u_int f_size; | |
529 | char *args = NULL; | |
530 | u_int c = 0; | |
531 | ||
532 | // loop through command line options and get options | |
533 | while(1) { | |
534 | int option_index = 0; | |
535 | c = getopt(argc, argv,"i:t:a:w:x:m:bdvh"); | |
536 | ||
537 | if (c==-1) break; | |
538 | switch(c) { | |
539 | case 0: | |
540 | break; | |
541 | case 'i': | |
542 | if (optarg) { | |
543 | if ( ( dev = (char *)strdup(optarg) ) == NULL) malloc_fail("dev", strlen(optarg) ); | |
544 | } | |
545 | break; | |
546 | case 't': | |
547 | if (optarg) { | |
548 | if ( abs (atoi(optarg)) > 0) { | |
549 | option_t = abs( atoi(optarg)); | |
550 | } | |
551 | } | |
552 | break; | |
553 | case 'a': | |
554 | if (optarg) { | |
555 | if ( abs (atoi(optarg)) > 10) { | |
556 | option_a = abs( atoi(optarg)); | |
557 | } | |
558 | } | |
559 | break; | |
560 | case 'w': | |
561 | if (optarg) { | |
562 | if ( abs (atoi(optarg)) > 1) { | |
563 | option_w = abs( atoi(optarg)); | |
564 | } | |
565 | } | |
566 | break; | |
567 | case 'x': | |
568 | if (optarg) { | |
569 | if ( abs (atoi(optarg)) > 10) { | |
570 | option_x = abs( atoi(optarg)); | |
571 | } | |
572 | } | |
573 | break; | |
574 | case 'm': | |
575 | if (optarg) { | |
576 | if ( abs (atoi(optarg)) > 0) { | |
577 | option_m = abs( atoi(optarg)); | |
578 | } | |
579 | } | |
580 | break; | |
581 | case 'b': | |
582 | option_b = 1; | |
583 | break; | |
584 | case 'd': | |
585 | option_d = 1; | |
586 | break; | |
587 | case 'v': | |
588 | option_v++; | |
589 | break; | |
590 | case 'h': | |
591 | option_h = 1; | |
592 | default: | |
593 | break; | |
594 | } | |
595 | } | |
596 | ||
597 | // display usage info if needed | |
598 | if (optind<argc) option_h = 1; | |
599 | if (option_h) { | |
600 | fprintf(stderr,"dns_flood_detector, version %s\n",VERSION); | |
601 | fprintf(stderr,"Usage: %s [OPTION]\n\n",argv[0]); | |
602 | fprintf(stderr,"-i IFNAME specify device name to listen on\n"); | |
603 | fprintf(stderr,"-t N alarm at >N queries per second\n"); | |
604 | fprintf(stderr,"-a N reset alarm after N seconds\n"); | |
605 | fprintf(stderr,"-w N calculate stats every N seconds\n"); | |
606 | fprintf(stderr,"-x N create N buckets\n"); | |
607 | fprintf(stderr,"-m N report overall stats every N seconds\n"); | |
608 | fprintf(stderr,"-b run in foreground in bindsnap mode\n"); | |
609 | fprintf(stderr,"-d run in background in daemon mode\n"); | |
610 | fprintf(stderr,"-v verbose output - use again for more verbosity\n"); | |
611 | fprintf(stderr,"-h display this usage information\n"); | |
612 | exit(1); | |
613 | } | |
614 | ||
615 | if ( ( ! option_d ) && ( ! option_b ) ) { | |
616 | fprintf(stderr,"%s couldn't start\n",argv[0]); | |
617 | fprintf(stderr,"You must specify either either -d (daemon) or -b (bindsnap)\n"); | |
618 | exit(1); | |
619 | } | |
620 | // set up for daemonized operation unless running in bindsnap mode | |
621 | if ( ! option_b ) { | |
622 | openlog("dns_flood_detector",LOG_PID|LOG_CONS,LOG_DAEMON); | |
623 | syslog(LOG_NOTICE,"dns_flood_detector starting"); | |
624 | ||
625 | // daemonize unless running in bindsnap mode | |
626 | daemonize(); | |
627 | ||
628 | // set up signal handlers | |
629 | sa.sa_handler=exit; | |
630 | sa.sa_flags=0; | |
631 | if(sigaction(SIGTERM,&sa,NULL)) { | |
632 | syslog(LOG_ERR,"Unable to set signal handler: %s. Exiting.", | |
633 | strerror(errno)); | |
634 | } | |
635 | } | |
636 | ||
637 | // find a valid device to open | |
638 | if(dev == NULL && ( (dev=pcap_lookupdev(errbuf)) == NULL ) ){ | |
639 | fprintf(stderr,"unable to bind to valid device\n"); | |
640 | exit(1); | |
641 | } | |
642 | ||
643 | // get network address and netmask for device | |
644 | pcap_lookupnet(dev,&netp,&maskp,errbuf); | |
645 | ||
646 | // set up filter with local network | |
647 | addr.s_addr = (unsigned long int)netp; | |
648 | if ( ( dst_addr = (char *)malloc( strlen((char *)inet_ntoa(addr))+1) ) == NULL ) malloc_fail("dest_addr", strlen((char *)inet_ntoa(addr))+1 ); | |
649 | strncpy(dst_addr,(char*)inet_ntoa(addr),strlen((char *)inet_ntoa(addr))); | |
650 | dst_addr[strlen((char *)inet_ntoa(addr))]='\0'; | |
651 | ||
652 | addr.s_addr = (unsigned long int)maskp; | |
653 | if ( ( dst_mask = (char *)malloc( strlen((char *)inet_ntoa(addr))+1) ) == NULL ) malloc_fail("dest_mask", strlen((char *)inet_ntoa(addr))+1 ); | |
654 | strncpy(dst_mask,(char*)inet_ntoa(addr),strlen((char *)inet_ntoa(addr))); | |
655 | dst_mask[strlen((char *)inet_ntoa(addr))]='\0'; | |
656 | ||
657 | f_size = strlen("port 53 and dst net mask ")+ strlen(dst_mask)+ strlen(dst_addr); | |
658 | if ( ( filter = (char *) malloc ( f_size+1) ) == NULL ) malloc_fail( "filter", f_size+1 ); | |
659 | snprintf( filter, f_size, "port 53 and dst net %s mask %s", dst_addr, dst_mask); | |
660 | ||
661 | free (dst_mask); | |
662 | free (dst_addr); | |
663 | ||
664 | // open device for reading only local traffic | |
665 | descr = pcap_open_live(dev,1500,0,1,errbuf); | |
666 | if(descr == NULL) { | |
667 | fprintf(stderr,"unable to open device %s\n",dev); | |
668 | exit(1); | |
669 | } | |
670 | ||
671 | // compile filter | |
672 | if(pcap_compile(descr,&fp,filter,0,netp) == -1) { | |
673 | exit(1); | |
674 | } | |
675 | ||
676 | // set filter | |
677 | if(pcap_setfilter(descr,&fp) == -1){ | |
678 | exit(1); | |
679 | } | |
680 | ||
681 | // initialize buckets and mark overall stats bucket | |
682 | init_buckets(); | |
683 | totals = option_x; | |
684 | ||
685 | // create mutex lock | |
686 | if (pthread_mutex_init(&stats_lock, NULL) < 0) { | |
687 | exit(1); | |
688 | } | |
689 | ||
690 | // launch watcher thread | |
691 | if (pthread_create (&thread, NULL, run_stats, (void *)0)) { | |
692 | exit(1); | |
693 | } | |
694 | ||
695 | // main pcap loop | |
696 | pcap_loop(descr,-1,handle_IP,args); | |
697 | ||
698 | // done | |
699 | closelog(); | |
700 | return 0; | |
701 | } | |
702 | ||
703 | // daemonize the process | |
704 | int daemonize(void) { | |
705 | pid_t pid; | |
706 | int fd; | |
707 | ||
708 | fd=open("/dev/null",O_RDWR); | |
709 | if(fd<0) { | |
710 | syslog(LOG_ERR,"Failed to open /dev/null: %s. Exiting.",strerror(errno)); | |
711 | exit(1); | |
712 | } | |
713 | ||
714 | dup2(fd,0); | |
715 | dup2(fd,1); | |
716 | dup2(fd,2); | |
717 | ||
718 | if((pid=fork())<0) { | |
719 | syslog(LOG_ERR,"Fork failed: %s. Exiting.",strerror(errno)); | |
720 | exit(1); | |
721 | } | |
722 | else if (pid!=0) { | |
723 | exit(0); | |
724 | } | |
725 | ||
726 | setsid(); | |
727 | chdir("/"); | |
728 | umask(0); | |
729 | return 0; | |
730 | } | |
731 | ||
732 | int malloc_fail( char * var, int size ) { | |
733 | // print error to stderr if running in bindsnap mode | |
734 | if (option_b) { | |
735 | fprintf(stderr, "our OS wouldn't let me malloc %d bytes for a new %s. giving up", size, var); | |
736 | } | |
737 | else { | |
738 | syslog(LOG_ERR, "our OS wouldn't let me malloc %d bytes for a new %s. giving up", size, var); | |
739 | } | |
740 | exit(1); | |
741 | } |
0 | /****************************************************************************** | |
1 | ||
2 | Program: dns_flood_detector.h | |
3 | Author: Dennis Opacki <dopacki@adotout.com> | |
4 | Date: Tue Mar 18 16:46:53 EST 2003 | |
5 | Purpose: Monitor DNS servers for abusive usage levels | |
6 | and alarm to syslog | |
7 | ||
8 | Copyright (C) 2003 Dennis Opacki | |
9 | ||
10 | This program is free software; you can redistribute it and/or modify | |
11 | it under the terms of the GNU General Public License as published by | |
12 | the Free Software Foundation; either version 2 of the License, or | |
13 | (at your option) any later version. | |
14 | ||
15 | This program is distributed in the hope that it will be useful, | |
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | GNU General Public License for more details. | |
19 | ||
20 | You should have received a copy of the GNU General Public License | |
21 | along with this program; if not, write to the Free Software | |
22 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
23 | ||
24 | *******************************************************************************/ | |
25 | ||
26 | // definitions | |
27 | #ifndef ETHER_HDRLEN | |
28 | #define ETHER_HDRLEN 14 | |
29 | #endif | |
30 | #define NS_MAXDNAME 1025 | |
31 | #define MAXSYSLOG 128 | |
32 | ||
33 | // evil Solaris hack | |
34 | #ifdef __sun__ | |
35 | typedef uint8_t u_int8_t; | |
36 | typedef uint16_t u_int16_t; | |
37 | typedef uint32_t u_int32_t; | |
38 | #endif | |
39 | ||
40 | // prototypes | |
41 | void handle_IP(u_char *args,const struct pcap_pkthdr* pkthdr,const u_char* packet); | |
42 | ||
43 | // data structures | |
44 | struct my_dns { | |
45 | u_int16_t dns_id; /* query identification number */ | |
46 | u_int8_t dns_flags1; /* first byte of flags */ | |
47 | u_int8_t dns_flags2; /* second byte of flags */ | |
48 | u_int16_t dns_qdcount; /* number of question entries */ | |
49 | u_int16_t dns_ancount; /* number of answer entries */ | |
50 | u_int16_t dns_nscount; /* number of authority entries */ | |
51 | u_int16_t dns_arcount; /* number of resource entries */ | |
52 | }; | |
53 | ||
54 | struct bucket { | |
55 | char * ip_addr; | |
56 | unsigned int tcp_count; | |
57 | unsigned int udp_count; | |
58 | unsigned int qps; | |
59 | int qstats[256]; | |
60 | time_t first_packet; | |
61 | time_t last_packet; | |
62 | time_t alarm_set; | |
63 | }; | |
64 |
0 | #! /bin/sh | |
1 | ||
2 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin | |
3 | ||
4 | test -f /usr/local/sbin/dns_flood_detector || exit 0 | |
5 | ||
6 | case "$1" in | |
7 | start) | |
8 | echo -n "Starting DNS flood detector: dns_flood_detector" | |
9 | start-stop-daemon --start --quiet --exec /usr/local/sbin/dns_flood_detector -- -d | |
10 | echo "." | |
11 | ;; | |
12 | stop) | |
13 | echo -n "Stopping DNS flood detector: dns_flood_detector" | |
14 | start-stop-daemon --stop --quiet --exec /usr/local/sbin/dns_flood_detector | |
15 | killall dns_flood_detector | |
16 | echo "." | |
17 | ;; | |
18 | restart|force-reload) | |
19 | echo -n "Restarting DNS flood detector: dns_flood_detector... " | |
20 | start-stop-daemon --stop --quiet --exec /usr/local/sbin/dns_flood_detector | |
21 | sleep 2 | |
22 | start-stop-daemon --stop --quiet --exec /usr/local/sbin/dns_flood_detector | |
23 | sleep 4 | |
24 | killall dns_flood_detector | |
25 | sleep 2 | |
26 | start-stop-daemon --start --quiet --exec /usr/local/sbin/dns_flood_detector -- -d | |
27 | echo "done." | |
28 | ;; | |
29 | *) | |
30 | echo "Usage: /etc/init.d/dnsflood {start|stop|restart|force-reload}" | |
31 | exit 1 | |
32 | ;; | |
33 | esac | |
34 | ||
35 | exit 0 |
0 | CFLAGS+=-O -g | |
1 | LDLIBS=-lpcap -pthread -lm | |
2 | ||
3 | all: dns_flood_detector | |
4 | strip dns_flood_detector | |
5 | clean: | |
6 | rm -rf dns_flood_detector *.o *~ | |
7 | install: | |
8 | cp dns_flood_detector /usr/local/sbin/ | |
9 | ||
10 | dns_flood_detector: dns_flood_detector.c |
0 | CFLAGS+=-O -g | |
1 | LDLIBS=-lpcap -pthread -lm | |
2 | ||
3 | all: dns_flood_detector | |
4 | strip dns_flood_detector | |
5 | clean: | |
6 | rm -rf dns_flood_detector *.o *~ | |
7 | install: | |
8 | cp dns_flood_detector /usr/local/sbin/ | |
9 | ||
10 | dns_flood_detector: dns_flood_detector.c |
0 | CFLAGS=-O -D_BSD_SOURCE -g | |
1 | LDLIBS=-lpcap -lpthread -lm | |
2 | ||
3 | all: dns_flood_detector | |
4 | strip dns_flood_detector | |
5 | clean: | |
6 | rm -rf dns_flood_detector *.o *~ | |
7 | install: | |
8 | cp dns_flood_detector /usr/local/sbin/ | |
9 | ||
10 | dns_flood_detector: dns_flood_detector.c |
0 | CFLAGS+=-O -g -I/usr/local/include -I/usr/include | |
1 | LDLIBS=-L/usr/local/lib -lpcap -lpthread -lm | |
2 | ||
3 | all: dns_flood_detector | |
4 | strip dns_flood_detector | |
5 | clean: | |
6 | rm -rf dns_flood_detector *.o *~ | |
7 | install: | |
8 | cp dns_flood_detector /usr/local/sbin/ | |
9 | ||
10 | dns_flood_detector: dns_flood_detector.c |
0 | CFLAGS+=-O -g -I/usr/local/include -I/usr/include | |
1 | LDLIBS=-L/usr/local/lib -L/usr/lib -lpcap -lpthread -lm -lsocket -lnsl | |
2 | ||
3 | all: dns_flood_detector | |
4 | strip dns_flood_detector | |
5 | clean: | |
6 | rm -rf dns_flood_detector *.o *~ | |
7 | install: | |
8 | cp dns_flood_detector /usr/local/sbin/ | |
9 | ||
10 | dns_flood_detector: dns_flood_detector.c |