From 0be9704d6b24d09ebd55beedec52758cb88c570b Mon Sep 17 00:00:00 2001 From: Kevin Webb Date: Mon, 20 Oct 2008 19:09:32 +0000 Subject: [PATCH] Importing all of DRL, including ulogd and all of its files. Everything DRL-related is included in the drl subdirectory. To be clear, ulogd is licensed under the GPL, and DRL is licensed under an academic license that can be found in the file drl/DRL-LICENSE. --- AUTHORS | 1 + COPYING | 343 ++ Changes | 129 + DistributedRateLimiting.spec | 1 + Makefile.in | 85 + README | 103 + Rules.make.in | 56 + TODO | 37 + aclocal.m4 | 130 + cftest/cftest.c | 30 + cftest/test.txt | 3 + conffile/Makefile.in | 21 + conffile/conffile.c | 241 + config.guess | 1407 ++++++ config.sub | 1505 ++++++ configure | 5979 +++++++++++++++++++++++ configure.in | 298 ++ contrib/ulog_query.php.gz | Bin 0 -> 2875 bytes doc/Makefile.in | 51 + doc/mysql.table | 55 + doc/mysql.table.ipaddr-as-string | 58 + doc/pgsql.table | 81 + doc/sqlite3.table | 22 + doc/ulogd.a4.ps | 4025 +++++++++++++++ doc/ulogd.html | 422 ++ doc/ulogd.sgml | 449 ++ doc/ulogd.txt | 580 +++ drl.xml | 6 + drl/DRL-LICENSE | 28 + drl/Doxyfile | 1252 +++++ drl/Makefile.in | 31 + drl/Manual.txt | 128 + drl/README | 637 +++ drl/bsd_queue.h | 627 +++ drl/calendar.h | 18 + drl/common_accounting.h | 83 + drl/config.c | 427 ++ drl/config.h | 161 + drl/drl_state.c | 223 + drl/drl_state.h | 250 + drl/estimate.c | 486 ++ drl/logging.c | 25 + drl/logging.h | 29 + drl/peer_comm.c | 613 +++ drl/peer_comm.h | 21 + drl/raterouter.h | 81 + drl/ratetypes.h | 245 + drl/samplehold.c | 339 ++ drl/samplehold.h | 165 + drl/simple.c | 81 + drl/simple.h | 58 + drl/standard.c | 314 ++ drl/standard.h | 150 + drl/ulogd_DRL.c | 1374 ++++++ drl/util.c | 360 ++ drl/util.h | 63 + extensions/Makefile.in | 37 + extensions/chtons.h | 32 + extensions/printpkt.c | 275 ++ extensions/printpkt.h | 7 + extensions/ulogd_BASE.c | 669 +++ extensions/ulogd_LOCAL.c | 101 + extensions/ulogd_LOGEMU.c | 136 + extensions/ulogd_OPRINT.c | 144 + extensions/ulogd_PWSNIFF.c | 167 + extensions/ulogd_SYSLOG.c | 149 + include/linux/jhash.h | 143 + include/ulogd/conffile.h | 66 + include/ulogd/gre.h | 34 + include/ulogd/ulogd.h | 162 + install-sh | 251 + libipulog/Makefile.in | 23 + libipulog/include/libipulog/libipulog.h | 58 + libipulog/libipulog.c | 276 ++ libipulog/ulog_test.c | 84 + mysql/Makefile | 30 + mysql/Makefile.in | 30 + mysql/ulogd_MYSQL.c | 454 ++ netflow/Makefile.in | 34 + netflow/ulogd_NETFLOW.c | 1512 ++++++ pcap/Makefile.in | 30 + pcap/ulogd_PCAP.c | 286 ++ pgsql/Makefile | 30 + pgsql/Makefile.in | 30 + pgsql/ulogd_PGSQL.c | 464 ++ sqlite3/Makefile | 30 + sqlite3/Makefile.in | 29 + sqlite3/ulogd_SQLITE3.c | 412 ++ ulogd.8 | 64 + ulogd.c | 825 ++++ ulogd.conf.in | 125 + ulogd.init | 62 + ulogd.logrotate | 7 + ulogd.spec | 179 + 94 files changed, 31834 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 Changes create mode 100644 Makefile.in create mode 100644 README create mode 100644 Rules.make.in create mode 100644 TODO create mode 100644 aclocal.m4 create mode 100644 cftest/cftest.c create mode 100644 cftest/test.txt create mode 100644 conffile/Makefile.in create mode 100644 conffile/conffile.c create mode 100755 config.guess create mode 100755 config.sub create mode 100755 configure create mode 100644 configure.in create mode 100644 contrib/ulog_query.php.gz create mode 100644 doc/Makefile.in create mode 100644 doc/mysql.table create mode 100644 doc/mysql.table.ipaddr-as-string create mode 100644 doc/pgsql.table create mode 100644 doc/sqlite3.table create mode 100644 doc/ulogd.a4.ps create mode 100644 doc/ulogd.html create mode 100644 doc/ulogd.sgml create mode 100644 doc/ulogd.txt create mode 100644 drl.xml create mode 100644 drl/DRL-LICENSE create mode 100644 drl/Doxyfile create mode 100644 drl/Makefile.in create mode 100644 drl/Manual.txt create mode 100644 drl/README create mode 100644 drl/bsd_queue.h create mode 100644 drl/calendar.h create mode 100644 drl/common_accounting.h create mode 100644 drl/config.c create mode 100644 drl/config.h create mode 100644 drl/drl_state.c create mode 100644 drl/drl_state.h create mode 100644 drl/estimate.c create mode 100644 drl/logging.c create mode 100644 drl/logging.h create mode 100644 drl/peer_comm.c create mode 100644 drl/peer_comm.h create mode 100644 drl/raterouter.h create mode 100644 drl/ratetypes.h create mode 100644 drl/samplehold.c create mode 100644 drl/samplehold.h create mode 100644 drl/simple.c create mode 100644 drl/simple.h create mode 100644 drl/standard.c create mode 100644 drl/standard.h create mode 100644 drl/ulogd_DRL.c create mode 100644 drl/util.c create mode 100644 drl/util.h create mode 100644 extensions/Makefile.in create mode 100644 extensions/chtons.h create mode 100644 extensions/printpkt.c create mode 100644 extensions/printpkt.h create mode 100644 extensions/ulogd_BASE.c create mode 100644 extensions/ulogd_LOCAL.c create mode 100644 extensions/ulogd_LOGEMU.c create mode 100644 extensions/ulogd_OPRINT.c create mode 100644 extensions/ulogd_PWSNIFF.c create mode 100644 extensions/ulogd_SYSLOG.c create mode 100644 include/linux/jhash.h create mode 100644 include/ulogd/conffile.h create mode 100644 include/ulogd/gre.h create mode 100644 include/ulogd/ulogd.h create mode 100755 install-sh create mode 100644 libipulog/Makefile.in create mode 100644 libipulog/include/libipulog/libipulog.h create mode 100644 libipulog/libipulog.c create mode 100644 libipulog/ulog_test.c create mode 100644 mysql/Makefile create mode 100644 mysql/Makefile.in create mode 100644 mysql/ulogd_MYSQL.c create mode 100644 netflow/Makefile.in create mode 100644 netflow/ulogd_NETFLOW.c create mode 100644 pcap/Makefile.in create mode 100644 pcap/ulogd_PCAP.c create mode 100644 pgsql/Makefile create mode 100644 pgsql/Makefile.in create mode 100644 pgsql/ulogd_PGSQL.c create mode 100644 sqlite3/Makefile create mode 100644 sqlite3/Makefile.in create mode 100644 sqlite3/ulogd_SQLITE3.c create mode 100644 ulogd.8 create mode 100644 ulogd.c create mode 100644 ulogd.conf.in create mode 100755 ulogd.init create mode 100644 ulogd.logrotate create mode 100644 ulogd.spec diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..dcc5998 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Harald Welte diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..fd58910 --- /dev/null +++ b/COPYING @@ -0,0 +1,343 @@ +NOTE: This license applies to ulogd, not DRL. See the drl +subdirectory for DRL information. + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Changes b/Changes new file mode 100644 index 0000000..95bc457 --- /dev/null +++ b/Changes @@ -0,0 +1,129 @@ +Version 1.24 (2006-01-25) +- Fix memory leak in postgresql plugin +- Fix printing of "PROTO=XX" for XX != (TCP,UDP,ICMP,ESP) +- Fix parsing of syslog log level +- Add support for 'mysql_config' and 'pg_config' programs +- Add support for 'lib64' to sqlite3 autoconf macros +- Fix some gcc-4 warnings +- Add reconnect support to mysql plugin +- Fix pcap header on some architectures +- Fix off-by-one-column error in sqlite3 plugin + +Version 1.23 (2005-04-18) +- Add supprt for ulogd logging in syslog (the daemon log, not packet log) + +Version 1.22 (2005-03-07) +- Fix postgresql endless loop (Jani Averbach) +- Add postgrsql schema support (Bob Hockney) + +Version 1.21 (2005-02-16) +- Fix compilation on certain gcc versions (Roberto Nibali) +- Fix --log-ip-as-string for mysql, pgsql and sqlite3 (Jani Averbach) + +Version 1.20 (2005-02-12) +- Add SQLITE3 Plugin +- Add 'port' option (for tcp port number) to mysql and postgresql plugins +- Cosmetic changes (c99 initializers, coding style) + +Version 1.10 (2003-Oct-xx) +- Change format of configuration file. Now every plugin has it's own section + in the config file, making the whole parsing procedure easier - and + eliminating multiple loading of .so plugins. (Magnus Boden) +- Make the config file format completely syntax compatible with .ini style files +- Add a new 'SYSLOG' plugin for real syslogging + +Version 1.02 (2003-Oct-08) +- fix printout of time information in ulogd_LOGEMU.c + +Version 1.01 (2003-Aug-23) +- use $(LD) macro in order to provide cross-compiling/linking support +- add 'rmem' configuration key to set the netlink socket rmem buffsize +- don't use kernel header files for IP/TCP header definitions +- various cosmetic cleanup to compile with -Wall +- fix usage of libmysqlclient: call mysql_init() before mysql_real_connect +- don't have LOGEMU read the system time, ulogd_LOCAL.so does this already + +Version 1.00 (2003-Mar-06) +- update documentation to reflect recent additions +- renamed LOCALTIME plugin to LOCAL plugin, since it now also returns + the hostname +- cleanup #include statements +- tcp.window is a 16bit value +- always return tcp flags, even if they are not set [to not cause NULL entries + in the database table +- cosmetic fixes to acommodate most compiler warnings +- moved location of conffile.h and ulog.h +- big update to ulogd_PGSQL.c +- more verbose error reporting when unable to load plugin +- print usage information +- add '--configfile' directive to allow multiple instances with multiple + configfiles + +Version 0.98 +- Fix MAC address printing if there is none (by Andrej Ota) +- Add PostgreSQL support by Jakab Laszlo +- Add Version Number (-V) commandline option +- Make MYBUFSIZ a runtime config directive (Bogdan Dobrota) +- Fix daemonize function (call setsid() and close stdin) +- Add ulogd_PCAP output plugin (to use ethereal/tcpdump/... on the logs) +- Update documentation to reflect kernel inclusion of ipt_ULOG module +- Add ulogd_LOCALTIME 'interpreter' for providing the timestamp at the + time of logging (Florent Aide) +- Fix ulogd_LOGEMU 'PROTO=' printing in case of unknown l4 protocol +- Add support for non-forking mode and logging to stderr (Alessandro Bono) + +Version 0.97 +- added error handling after ipulog_read() to prevent endless loops + +Version 0.96 +- support for old mysql versions (Alexander Janssen) +- support for dotted-quad IP addresses in MySQL (Alexander Janssen) +- added support for synchronous write to LOGEMU (Michael Stolovitzsky) +- autoconf now checks for mysql .so libraries instead of static .a +- autoconf now includes /usr/src/linux/include, because most distros + now have a glibc-provided /usr/include/linux :( +- removed ./configure from CVS tree as it may cause inconsistencies +- better commented example configuration file +- Makefiles now know DESTDIR (for RPM packaging) +- documentation now built at release-time, not compile time +- support for logfile-rotating, using new SIGHUP handler + +Version 0.95 +- libipulog problems of 0.94 fixed +- 1.0 now really soon + +Version 0.94 +- fixed stupid build problem because of missing libipulog + (i'll never try to be intelligent again ;)) + +Version 0.93 +- fixes logfile bug: wrong filename and line numbers printed +- fixes config file parsing, new generic get_word() in conffile.c +- fixes bug in ulogd_LOGEMU.c on big-endian systems +- fixes segfault when packet received but no interpreters registered + (reported by Drori Ghiora) +- sigterm handler installed for clean shutdown +- logfile now fflush()ed after each line printed +- ulogd_LOGEMU now prints date and hostname, just as syslog does + +Version 0.92 +- fixes libipulog loop-bug (reported by Drori Ghiora) + +Version 0.91 +- changes for new kernel ULOG. Includes support for multilink netlink + messages. + +Version 0.9 +- configuration file routines +- plugins are able to register new configfile keys +- new MYSQL output plugin +- new syslog compatibility output plugin + +Version 0.3 + +- new PWSNIFF interpreter plugin +- verbose error reporting + +Version 0.2 + +- real daemon, we are forking now diff --git a/DistributedRateLimiting.spec b/DistributedRateLimiting.spec index a08afda..b8ac831 100644 --- a/DistributedRateLimiting.spec +++ b/DistributedRateLimiting.spec @@ -53,6 +53,7 @@ rm -rf %{buildroot} %attr(0755,root,root) %{_sbindir}/ulogd %attr(0755,root,root) %{_bindir}/netflow-import %{_sysconfdir}/ulogd.conf +%{_sysconfdir}/drl.xml %{_sysconfdir}/logrotate.d/ulogd %attr(0755,root,root) %{_sysconfdir}/rc.d/init.d/ulogd %{_mandir}/man8/* diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..618d44c --- /dev/null +++ b/Makefile.in @@ -0,0 +1,85 @@ +RELEASE_DIR:=/tmp + +include @top_srcdir@/Rules.make +CFLAGS+=-I@top_srcdir@/libipulog/include -I@top_srcdir@/include + +SUBDIRS=conffile libipulog extensions doc drl + +ifeq (x@MYSQLINCLUDES@,x) +else +SUBDIRS+=mysql +endif + +ifeq (x@PGSQLINCLUDES@,x) +else +SUBDIRS+=pgsql +endif + +ifeq (x@HAVE_PCAP_H@,x) +else +#SUBDIRS+=pcap +endif + +ULOGD_VERSION=1.24 +OLD_ULOGD_VERSION=1.23 + +ifeq (x@SQLITE3INCLUDES@,x) +else +SUBDIRS+=sqlite3 +endif + +# Normally You should not need to change anything below + +all: recurse ulogd + +.PHONY: distclean +distclean: clean + @for d in $(SUBDIRS); do if ! make -C $$d $@; then exit 1; fi; done + rm -f Makefile config.cache config.log config.status Rules.make + +.PHONY: docbuild +docbuild: + make -C doc distrib + +.PHONY: distrib +distrib: docbuild distclean delrelease $(RELEASE_DIR)/ulogd-$(ULOGD_VERSION).tar.bz2 diff + +.PHONY: delrelease +delrelease: + rm -f $(RELEASE_DIR)/ulogd-$(ULOGD_VERSION).tar.bz2 + +$(RELEASE_DIR)/ulogd-$(ULOGD_VERSION).tar.bz2: + cd .. && ln -sf ulogd ulogd-$(ULOGD_VERSION) && tar cvf - --exclude CVS --exclude .svn ulogd-$(ULOGD_VERSION)/. | bzip2 -9 > $@ && rm ulogd-$(ULOGD_VERSION) + +.PHONY: diff +diff: $(RELEASE_DIR)/ulogd-$(ULOGD_VERSION).tar.bz2 + @[ -d /tmp/diffdir ] || mkdir /tmp/diffdir + @cd /tmp/diffdir && tar -x --bzip2 -f $(RELEASE_DIR)/ulogd-$(ULOGD_VERSION).tar.bz2 + @set -e; cd /tmp/diffdir; tar -x --bzip2 -f $(RELEASE_DIR)/ulogd-$(OLD_ULOGD_VERSION).tar.bz2; echo Creating patch-ulogd-$(OLD_ULOGD_VERSION)-$(ULOGD_VERSION).bz2; diff -urN ulogd-$(OLD_ULOGD_VERSION) ulogd-$(ULOGD_VERSION) | bzip2 -9 > $(RELEASE_DIR)/patch-ulogd-$(OLD_ULOGD_VERSION)-$(ULOGD_VERSION).bz2 + @rm -rf /tmp/diffdir + +recurse: + @for d in $(SUBDIRS); do if ! make -C $$d; then exit 1; fi; done + +ulogd: ulogd.c include/ulogd/ulogd.h ulogd.conf recurse + $(CC) $(CFLAGS) -rdynamic $< conffile/conffile.o $(LIBIPULOG)/libipulog.a -o $@ $(LDFLAGS) $(LIBS) `xml2-config --libs` + +edit = sed -e 's,@libdir\@,$(ULOGD_LIB_PATH),g' + +ulogd.conf: ulogd.conf.in + $(edit) ulogd.conf.in > ulogd.conf + +clean: +# rm -f ulogd *.o extensions/*.o extensions/*.so conffile/*.o + rm -f ulogd ulogd.o ulogd.conf + @for d in $(SUBDIRS); do if ! make -C $$d $@; then exit 1; fi; done + +install: all + @for d in $(SUBDIRS); do if ! make -C $$d $@; then exit 1; fi; done + @[ -d $(DESTDIR)$(BINDIR) ] || mkdir -p $(DESTDIR)$(BINDIR) + @INSTALL@ -D -m 755 ulogd $(DESTDIR)$(BINDIR)/ulogd + @[ -d $(DESTDIR)$(ETCDIR) ] || mkdir -p $(DESTDIR)$(ETCDIR) + @[ -f $(DESTDIR)$(ETCDIR)/ulogd.conf ] || @INSTALL@ -D -m 600 ulogd.conf $(DESTDIR)$(ETCDIR)/ulogd.conf + +doc: + $(MAKE) -C $@ diff --git a/README b/README new file mode 100644 index 0000000..991cc65 --- /dev/null +++ b/README @@ -0,0 +1,103 @@ + +NOTE: This is the README for ulogd, not DRL. All of the DRL-related +code and documentation is located in the drl subdirectory. + +------------------------------------------------------------------------------ + +Userspace logging facility for iptables / linux 2.4 +$Id: README 4896 2003-03-05 23:03:49Z laforge $ + +Project Homepage: http://www.gnumonks.org/projects/ulogd +Mailinglist: http://lists.gnumonks.org/mailman/listinfo/ulogd/ + +This is just a short README, pleaes see the more extensive documentation +in the doc/ subdirectory. + +===> IDEA + +This packages is intended for passing packets from the kernel to userspace +to do some logging there. It should work like that: + +- Register a target called ULOG with iptables +- if the target is hit: + - send the packet out using netlink multicast facility + - return NF_CONTINUE immediately + +New with ipt_ULOG 0.8 we can accumulate packets in userspace and send +them in small batches (1-50) to userspace. This reduces the amount of +expensive context switches. + +More than one logging daemon may listen to the netlink multicast address. + +===> CONTENTS + += Ulog library (libipulog.a) +Just a little library like libipq.a which provides a convenient way to +write userspace logging daemons. The functions provided are described +in the source code, a small demo program (ulog_test) is also included. + += ulogd daemon (ulogd) +A sophisticated logging daemon which uses libipulog. The daemon provides +an easy to use plugin interface to write additional packet interpreters and +output targets. Example plugins (interpreter: ip, tcp, icmp output: simple +logging to a file) are included. + += documentation (doc) +A quite verbose documentation of this package and it's configuration exists, +please actually make use of it and read it :) + +===> USAGE + +The kernel part of the userspace logging facility (ipt_ULOG.o) is included +in kernels >= 2.4.18-pre8. If you are running older kernel versions, you MUST +install the ulog-patch from netfilter patch-o-matic FIRST !! + +Please go to the netfilter homepage (http://www.netfilter.org/) +and download the latest iptables package. There is a system called +patch-o-matic, which manages recent netfilter development, which has +not been included in the stock kernel yet. + +Just apply the ulog-patch from patch-o-matic (there is some documentation +included in the iptables package how to use patch-o-matic). + +Next you have to enable the kernel config option CONFIG_IP_NF_TARGET_ULOG in +the netfilter subsection of the network options. + +Then recompile the kernel or just recompile the netfilter modules using 'make +modules SUBDIRS=net/ipv4/netfilter'. Next step is installing the module using +'make modules_install' + +It is also a good idea to recompile and re-install the iptables package, +if you don't already have libipt_ULOG.so in /usr/local/lib/iptables or +/usr/lib/iptables + +Now You are ready to go. You may now insert logging rules to every chain. +To see the full syntax, type 'iptables -j ULOG -h' + +===> EXAMPLES + +At first a simple example, which passes every outgoing packet to the +userspace logging, using netlink multicast group 3. + +iptables -A OUTPUT -j ULOG --ulog-nlgroup 3 + +A more advanced one, passing all incoming tcp packets with destination +port 80 to the userspace logging daemon listening on netlink multicast +group 32. All packets get tagged with the ulog prefix "inp" + +iptables -A INPUT -j ULOG -p tcp --dport 80 --ulog-nlgroup 32 --ulog-prefix inp + +Since version 0.2, I added another parameter (--ulog-cprange). +Using this parameter You are able to specify how much octets of the +packet should be copied from the kernel to userspace. +Setting --ulog-cprange to 0 does always copy the whole packet. Default is 0 + +===> COPYRIGHT + CREDITS + +The code is (C) 2000-2003 by Harald Welte + +Thanks also to the valuable Contributions of Daniel Stone, Alexander +Janssen and Michael Stolovitzsky. + +Credits to Rusty Russel, James Morris, Marc Boucher and all the other +netfilter hackers. diff --git a/Rules.make.in b/Rules.make.in new file mode 100644 index 0000000..99a7f1a --- /dev/null +++ b/Rules.make.in @@ -0,0 +1,56 @@ +# + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +ETCDIR=@sysconfdir@ +BINDIR=@sbindir@ +bindir=@bindir@ + +ULOGD_CONFIGFILE=@sysconfdir@/ulogd.conf + +ULOGD_LIB_PATH=@libdir@/ulogd + +# Path of libipulog (from iptables) +LIBIPULOG=@top_srcdir@/libipulog +INCIPULOG=-I@top_srcdir@/libipulog/include +INCCONFFILE=-I@top_srcdir@/conffile + +CC=@CC@ +LD=@LD@ +INSTALL=@INSTALL@ + +CFLAGS=@CFLAGS@ @CPPFLAGS@ -Wall +CFLAGS+=-DULOGD_CONFIGFILE=\"$(ULOGD_CONFIGFILE)\" +# doesn't work for subdirs +#CFLAGS+=$(INCIPULOG) $(INCCONFFILE) +CFLAGS+=-I@KSRC@/include +CFLAGS+=@DEFS@ -Wall +#CFLAGS+=-g -DDEBUG -DDEBUG_MYSQL -DDEBUG_PGSQL +LDFLAGS+=@LDFLAGS@ + +ifneq "$(shell ld --help | grep build-id)" "" +CFLAGS += -Wl,--build-id +LD += --build-id +endif + +LIBS=@LIBS@ + + +# Names of the plugins to be compiled +ULOGD_SL:=BASE OPRINT PWSNIFF LOGEMU LOCAL SYSLOG + +# mysql output support +#ULOGD_SL+=MYSQL +MYSQL_CFLAGS=-I@MYSQLINCLUDES@ @EXTRA_MYSQL_DEF@ +MYSQL_LDFLAGS=@DATABASE_LIB_DIR@ @MYSQL_LIB@ + +# postgreSQL output support +#ULOGD_SL+=PGSQL +PGSQL_CFLAGS=-I@PGSQLINCLUDES@ @EXTRA_PGSQL_DEF@ +PGSQL_LDFLAGS=@DATABASE_LIB_DIR@ @PGSQL_LIB@ + +# mysql output support +#ULOGD_SL+=SQLITE3 +SQLITE3_CFLAGS=-I@SQLITE3INCLUDES@ @EXTRA_SQLITE3_DEF@ +SQLITE3_LDFLAGS=@DATABASE_LIB_DIR@ @SQLITE3_LIB@ + diff --git a/TODO b/TODO new file mode 100644 index 0000000..3ab6194 --- /dev/null +++ b/TODO @@ -0,0 +1,37 @@ +libipulog: +X handle multi-part nlmsgs +- Error checking at netlink socket +- forward port my timeout enabled read-function from libipq to libipulog +- man pages + +kernel: +X queue the logging in the kernel and send multiple packets in one + multipart nlmsg +X add timer to flush queue in user-defineable time intervals +- IPv6 ULOG target + +ulogd: +X MYSQL output plugin +X syslog compatibility output plugin +- autoconf-detection of ipt_ULOG.h +X _fini() support for plugin destructors (needed for clean shutdown and + SIGHUP configfile reload +X commandline option for "to fork or not to fork" +X various command line options (we don't even have --version) +- add support for capabilities to run as non-root +X big endian fixes +X man pages +- IPv6 support (core and extensions) +X pcap output plugin (to use ethereal/tcpdump/... for the logs) +- enable user to specify directory where to look for kernel include files +- support for static linking +- make core maintain a list of keyid's that all the output plugins are + interested. The interpreters would be called with their respective + section of that list, and only compute those values that are actually + used by any of the running output plugins +- issues with ulogd_BASE and partially copied packets (--ulog-cprange) +- problem wrt. ulogd_BASE and fragments +- implement extension SIGHUP handlers (including config re-parse) + +conffile: +- rewrite parser. This stuff is a real mess. Anybody interested? diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..368464b --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,130 @@ +dnl aclocal.m4 generated automatically by aclocal 1.4 + +dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + +dnl aclocal.m4 generated automatically by aclocal 1.4 + +dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + +# Do all the work for Automake. This macro actually does too much -- +# some checks are only needed if your package does certain things. +# But this isn't really a big deal. + +# serial 1 + +dnl Usage: +dnl AM_INIT_AUTOMAKE(package,version, [no-define]) + +AC_DEFUN(AM_INIT_AUTOMAKE, +[AC_REQUIRE([AC_PROG_INSTALL]) +PACKAGE=[$1] +AC_SUBST(PACKAGE) +VERSION=[$2] +AC_SUBST(VERSION) +dnl test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi +ifelse([$3],, +AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) +AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])) +AC_REQUIRE([AM_SANITY_CHECK]) +AC_REQUIRE([AC_ARG_PROGRAM]) +dnl FIXME This is truly gross. +missing_dir=`cd $ac_aux_dir && pwd` +AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) +AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) +AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) +AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) +AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) +AC_REQUIRE([AC_PROG_MAKE_SET])]) + +# +# Check to make sure that the build environment is sane. +# + +AC_DEFUN(AM_SANITY_CHECK, +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "[$]*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "[$]*" != "X $srcdir/configure conftestfile" \ + && test "[$]*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "[$]2" = conftestfile + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +rm -f conftest* +AC_MSG_RESULT(yes)]) + +dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) +dnl The program must properly implement --version. +AC_DEFUN(AM_MISSING_PROG, +[AC_MSG_CHECKING(for working $2) +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if ($2 --version) < /dev/null > /dev/null 2>&1; then + $1=$2 + AC_MSG_RESULT(found) +else + $1="$3/missing $2" + AC_MSG_RESULT(missing) +fi +AC_SUBST($1)]) + + +# Define a conditional. + +AC_DEFUN(AM_CONDITIONAL, +[AC_SUBST($1_TRUE) +AC_SUBST($1_FALSE) +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi]) + diff --git a/cftest/cftest.c b/cftest/cftest.c new file mode 100644 index 0000000..b99882b --- /dev/null +++ b/cftest/cftest.c @@ -0,0 +1,30 @@ +#include +#include +#include "conffile.h" + +int bla(char *args) +{ + printf("bla called: %s\n", args); + return 0; +} +int main() +{ + config_entry_t e,f; + memset(&e, 0, sizeof(config_entry_t)); + strcpy(e.key, "zeile"); + e.u.parser = bla; + e.type = CONFIG_TYPE_CALLBACK; + config_register_key(&e); + + strcpy(f.key, "spalte"); + f.type = CONFIG_TYPE_STRING; + f.options |= CONFIG_OPT_MANDATORY; + f.u.str.string = (char *) malloc(100); + f.u.str.maxlen = 99; + config_register_key(&f); + + config_parse_file("test.txt"); + printf("SPALTE: %s\n", f.u.str.string); + + exit(0); +} diff --git a/cftest/test.txt b/cftest/test.txt new file mode 100644 index 0000000..3c0b663 --- /dev/null +++ b/cftest/test.txt @@ -0,0 +1,3 @@ +zeile zeile1 +spalte 0815 +asdfasf diff --git a/conffile/Makefile.in b/conffile/Makefile.in new file mode 100644 index 0000000..907e6a7 --- /dev/null +++ b/conffile/Makefile.in @@ -0,0 +1,21 @@ +# + +include @top_srcdir@/Rules.make +CFLAGS+=-I@top_srcdir@/include/ulogd + +# Normally You should not need to change anything below + +all: conffile.o + +distrib: + +conffile.o: conffile.c + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f conffile.o + +distclean: + rm -f Makefile + +install: all diff --git a/conffile/conffile.c b/conffile/conffile.c new file mode 100644 index 0000000..bf8b74c --- /dev/null +++ b/conffile/conffile.c @@ -0,0 +1,241 @@ +/* config file parser functions + * + * (C) 2000 by Harald Welte + * + * $Id: conffile.c 4946 2003-09-28 15:19:25Z laforge $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include "conffile.h" + +#ifdef DEBUG_CONF +#define DEBUGC(format, args...) fprintf(stderr, format, ## args) +#else +#define DEBUGC(format, args...) +#endif + +/* points to config entry with error */ +config_entry_t *config_errce = NULL; + +/* Filename of the config file */ +static char *fname = NULL; + +/* get_word() - Function to parse a line into words. + * Arguments: line line to parse + * delim possible word delimiters + * buf pointer to buffer where word is returned + * Return value: pointer to first char after word + * This function can deal with "" quotes + */ +static char *get_word(char *line, char *not, char *buf) +{ + char *p, *start = NULL, *stop = NULL; + int inquote = 0; + + for (p = line; *p; p++) { + if (*p == '"') { + start = p + 1; + inquote = 1; + break; + } + if (!strchr(not, *p)) { + start = p; + break; + } + } + if (!start) + return NULL; + + /* determine pointer to one char after word */ + for (p = start; *p; p++) { + if (inquote) { + if (*p == '"') { + stop = p; + break; + } + } else { + if (strchr(not, *p)) { + stop = p; + break; + } + } + } + if (!stop) + return NULL; + + strncpy(buf, start, (size_t) (stop-start)); + *(buf + (stop-start)) = '\0'; + + /* skip quote character */ + if (inquote) + /* yes, we can return stop + 1. If " was the last + * character in string, it now points to NULL-term */ + return (stop + 1); + + return stop; +} + +#if 0 +/* do we have a config directive for this name */ +static int config_iskey(char *name) +{ + config_entry_t *ce; + + for (ce = config; ce; ce = ce->next) { + if (!strcmp(name, ce->key)) + return 0; + } + + return 1; +} +#endif + +/*********************************************************************** + * PUBLIC INTERFACE + ***********************************************************************/ + +/* register config file with us */ +int config_register_file(const char *file) +{ + /* FIXME: stat of file */ + if (fname) + return 1; + + fname = (char *) malloc(strlen(file)+1); + if (!fname) + return -ERROOM; + + strcpy(fname, file); + + return 0; +} + +/* parse config file */ +int config_parse_file(const char *section, config_entry_t *keys) +{ + FILE *cfile; + char *args; + config_entry_t *ce; + int err = 0; + int found = 0; + char linebuf[LINE_LEN+1]; + char *line = linebuf; + + cfile = fopen(fname, "r"); + if (!cfile) + return -ERROPEN; + + DEBUGC("prasing section [%s]\n", section); + + /* Search for correct section */ + while (fgets(line, LINE_LEN, cfile)) { + char wordbuf[LINE_LEN]; + char *wordend; + + if (*line == '#') + continue; + + if (!(wordend = get_word(line, " \t\n[]", (char *) wordbuf))) + continue; + DEBUGC("word: \"%s\"\n", wordbuf); + if (!strcmp(wordbuf, section)) { + found = 1; + break; + } + } + + if (!found) { + fclose(cfile); + return -ERRSECTION; + } + + /* Parse this section until next section */ + while (fgets(line, LINE_LEN, cfile)) + { + char wordbuf[LINE_LEN]; + char *wordend; + + DEBUGC("line read: %s\n", line); + if (*line == '#') + continue; + + if (!(wordend = get_word(line, " =\t\n", (char *) &wordbuf))) + continue; + + if (wordbuf[0] == '[' ) { + DEBUGC("Next section '%s' encountered\n", wordbuf); + break; + } + + DEBUGC("parse_file: entering main loop\n"); + for (ce = keys; ce; ce = ce->next) { + DEBUGC("parse main loop, key: %s\n", ce->key); + if (strcmp(ce->key, (char *) &wordbuf)) { + continue; + } + + wordend = get_word(wordend, " =\t\n", (char *) &wordbuf); + args = (char *)&wordbuf; + + if (ce->hit && !(ce->options & CONFIG_OPT_MULTI)) + { + DEBUGC("->ce-hit and option not multi!\n"); + config_errce = ce; + err = -ERRMULT; + goto cpf_error; + } + ce->hit++; + + switch (ce->type) { + case CONFIG_TYPE_STRING: + if (strlen(args) < + CONFIG_VAL_STRING_LEN ) { + strcpy(ce->u.string, args); + /* FIXME: what if not ? */ + } + break; + case CONFIG_TYPE_INT: + ce->u.value = atoi(args); + break; + case CONFIG_TYPE_CALLBACK: + (ce->u.parser)(args); + break; + } + break; + } + DEBUGC("parse_file: exiting main loop\n"); + } + + + for (ce = keys; ce; ce = ce->next) { + DEBUGC("ce post loop, ce=%s\n", ce->key); + if ((ce->options & CONFIG_OPT_MANDATORY) && (ce->hit == 0)) { + DEBUGC("Mandatory config directive \"%s\" not found\n", + ce->key); + config_errce = ce; + err = -ERRMAND; + goto cpf_error; + } + + } + +cpf_error: + fclose(cfile); + return err; +} + diff --git a/config.guess b/config.guess new file mode 100755 index 0000000..0e30d56 --- /dev/null +++ b/config.guess @@ -0,0 +1,1407 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + +timestamp='2003-07-02' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Per Bothner . +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit 0 ;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + macppc:OpenBSD:*:*) + echo powerpc-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvmeppc:OpenBSD:*:*) + echo powerpc-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mipseb-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sun3:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit 0 ;; + Alpha*:OpenVMS:*:*) + echo alpha-hp-vms + exit 0 ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit 0;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit 0 ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit 0 ;; + DRS?6000:UNIX_SV:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7 && exit 0 ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit 0 ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit 0 ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c \ + && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && exit 0 + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit 0 ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit 0 ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + # avoid double evaluation of $set_cc_for_build + test -n "$CC_FOR_BUILD" || eval $set_cc_for_build + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + *:UNICOS/mp:*:*) + echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*|*:GNU/FreeBSD:*:*) + # Determine whether the default compiler uses glibc. + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #if __GLIBC__ >= 2 + LIBC=gnu + #else + LIBC= + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + # GNU/FreeBSD systems have a "k" prefix to indicate we are using + # FreeBSD's kernel, but not the complete OS. + case ${LIBC} in gnu) kernel_only='k' ;; esac + echo ${UNAME_MACHINE}-unknown-${kernel_only}freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC} + exit 0 ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit 0 ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit 0 ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit 0 ;; + x86:Interix*:[34]*) + echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' + exit 0 ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit 0 ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit 0 ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit 0 ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit 0 ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 + ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit 0 ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit 0 ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit 0 ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit 0 ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit 0 ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit 0 ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit 0 ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit 0 ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit 0 ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit 0 ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #ifdef __INTEL_COMPILER + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0 + test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit 0 ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit 0 ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit 0 ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit 0 ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit 0 ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit 0 ;; + i*86:*:5:[78]*) + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit 0 ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit 0 ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit 0 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit 0 ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit 0 ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit 0 ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit 0 ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit 0 ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Darwin:*:*) + case `uname -p` in + *86) UNAME_PROCESSOR=i686 ;; + powerpc) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit 0 ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit 0 ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit 0 ;; + NSR-[DGKLNPTVW]:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit 0 ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit 0 ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit 0 ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit 0 ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit 0 ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit 0 ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit 0 ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit 0 ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit 0 ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit 0 ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit 0 ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0 + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.sub b/config.sub new file mode 100755 index 0000000..6eea727 --- /dev/null +++ b/config.sub @@ -0,0 +1,1505 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + +timestamp='2003-07-17' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit 0;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | kfreebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32r | m68000 | m68k | m88k | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | msp430 \ + | ns16k | ns32k \ + | openrisc | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \ + | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xscale | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* \ + | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32r-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | msp430-* \ + | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ + | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ + | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + mmix*) + basic_machine=mmix-knuth + os=-mmixware + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nv1) + basic_machine=nv1-cray + os=-unicosmp + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + or32 | or32-*) + basic_machine=or32-unknown + os=-coff + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparc | sparcv9 | sparcv9b) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -kfreebsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-ibm) + os=-aix + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure b/configure new file mode 100755 index 0000000..b3b6485 --- /dev/null +++ b/configure @@ -0,0 +1,5979 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.59. +# +# Copyright (C) 2003 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_config_libobj_dir=. +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +ac_unique_file="ulogd.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif +#if HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS SET_MAKE CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT LD ac_ct_LD INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CPP EGREP KSRC KVER MYSQLINCLUDES MYSQL_LIB PGSQLINCLUDES PGSQL_LIB DATABASE_DIR DATABASE_LIB DATABASE_LIB_DIR DB_DEF EXTRA_MYSQL_DEF EXTRA_PGSQL_DEF DATABASE_DRIVERS HAVE_PCAP_H HAVE_MYSQL_TRUE HAVE_MYSQL_FALSE HAVE_PGSQL_TRUE HAVE_PGSQL_FALSE LIBOBJS LTLIBOBJS' +ac_subst_files='' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || + { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 + { (exit 1); exit 1; }; } +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +_ACEOF + + cat <<_ACEOF +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) +--with-kernel=DIR kernel source directory +--with-proper= proper installed in +--with-mysql= mysql installed in +--with-mysql-log-ip-as-string log IPs as string rather than as + unsigned long-integer. + +--with-pgsql= pgsql installed in +--with-pgsql-log-ip-as-string log IPs as string rather than as interger + + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +_ACEOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + cd $ac_dir + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_srcdir/configure.gnu; then + echo + $SHELL $ac_srcdir/configure.gnu --help=recursive + elif test -f $ac_srcdir/configure; then + echo + $SHELL $ac_srcdir/configure --help=recursive + elif test -f $ac_srcdir/configure.ac || + test -f $ac_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi + cd $ac_popdir + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\_ACEOF + +Copyright (C) 2003 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit 0 +fi +exec 5>config.log +cat >&5 <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.59. Invocation command line was + + $ $0 $@ + +_ACEOF +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_sep= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + # Get rid of the leading space. + ac_sep=" " + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Be sure not to use single quotes in there, as some shells, +# such as our DU 5.0 friend, will then `close' the trap. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------- ## +## Output files. ## +## ------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + sed "/^$/d" confdefs.h | sort + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core && + rm -rf conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + + + + + +echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +all: + @echo 'ac_maketemp="$(MAKE)"' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftest.make +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + SET_MAKE= +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. + +# Be careful to initialize this variable, since it used to be cached. +# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. +ac_cv_exeext= +# b.out is created by i960 compilers. +for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) + ;; + conftest.$ac_ext ) + # This is the source file. + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool, + # but it would be cool to find out if it's true. Does anybody + # maintain Libtool? --akim. + export ac_cv_exeext + break;; + * ) + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std1 is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std1. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ld", so it can be a program name with args. +set dummy ${ac_tool_prefix}ld; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_LD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$LD"; then + ac_cv_prog_LD="$LD" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_LD="${ac_tool_prefix}ld" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +LD=$ac_cv_prog_LD +if test -n "$LD"; then + echo "$as_me:$LINENO: result: $LD" >&5 +echo "${ECHO_T}$LD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_LD"; then + ac_ct_LD=$LD + # Extract the first word of "ld", so it can be a program name with args. +set dummy ld; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_LD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_LD"; then + ac_cv_prog_ac_ct_LD="$ac_ct_LD" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_LD="ld" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_LD=$ac_cv_prog_ac_ct_LD +if test -n "$ac_ct_LD"; then + echo "$as_me:$LINENO: result: $ac_ct_LD" >&5 +echo "${ECHO_T}$ac_ct_LD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + LD=$ac_ct_LD +else + LD="$ac_cv_prog_LD" +fi + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f $ac_dir/shtool; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 +echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} + { (exit 1); exit 1; }; } +fi +ac_config_guess="$SHELL $ac_aux_dir/config.guess" +ac_config_sub="$SHELL $ac_aux_dir/config.sub" +ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + + + +echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 +echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6 +if test "${ac_cv_lib_dl_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dl_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dl_dlopen=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6 +if test $ac_cv_lib_dl_dlopen = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBDL 1 +_ACEOF + + LIBS="-ldl $LIBS" + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6 +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6 +if test "${ac_cv_prog_egrep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 +echo "${ECHO_T}$ac_cv_prog_egrep" >&6 + EGREP=$ac_cv_prog_egrep + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +if test "${ac_cv_header_pcap_h+set}" = set; then + echo "$as_me:$LINENO: checking for pcap.h" >&5 +echo $ECHO_N "checking for pcap.h... $ECHO_C" >&6 +if test "${ac_cv_header_pcap_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_pcap_h" >&5 +echo "${ECHO_T}$ac_cv_header_pcap_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking pcap.h usability" >&5 +echo $ECHO_N "checking pcap.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking pcap.h presence" >&5 +echo $ECHO_N "checking pcap.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: pcap.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: pcap.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: pcap.h: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: pcap.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: pcap.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: pcap.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: pcap.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: pcap.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: pcap.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: pcap.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: pcap.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: pcap.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: pcap.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: pcap.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: pcap.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: pcap.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------ ## +## Report this to the AC_PACKAGE_NAME lists. ## +## ------------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for pcap.h" >&5 +echo $ECHO_N "checking for pcap.h... $ECHO_C" >&6 +if test "${ac_cv_header_pcap_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_pcap_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_pcap_h" >&5 +echo "${ECHO_T}$ac_cv_header_pcap_h" >&6 + +fi +if test $ac_cv_header_pcap_h = yes; then + HAVE_PCAP_H=true +fi + + + + + + + + +ac_header_dirent=no +for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do + as_ac_Header=`echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_hdr that defines DIR" >&5 +echo $ECHO_N "checking for $ac_hdr that defines DIR... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include <$ac_hdr> + +int +main () +{ +if ((DIR *) 0) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 +_ACEOF + +ac_header_dirent=$ac_hdr; break +fi + +done +# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. +if test $ac_header_dirent = dirent.h; then + echo "$as_me:$LINENO: checking for library containing opendir" >&5 +echo $ECHO_N "checking for library containing opendir... $ECHO_C" >&6 +if test "${ac_cv_search_opendir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_func_search_save_LIBS=$LIBS +ac_cv_search_opendir=no +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char opendir (); +int +main () +{ +opendir (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_opendir="none required" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test "$ac_cv_search_opendir" = no; then + for ac_lib in dir; do + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char opendir (); +int +main () +{ +opendir (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_opendir="-l$ac_lib" +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done +fi +LIBS=$ac_func_search_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_search_opendir" >&5 +echo "${ECHO_T}$ac_cv_search_opendir" >&6 +if test "$ac_cv_search_opendir" != no; then + test "$ac_cv_search_opendir" = "none required" || LIBS="$ac_cv_search_opendir $LIBS" + +fi + +else + echo "$as_me:$LINENO: checking for library containing opendir" >&5 +echo $ECHO_N "checking for library containing opendir... $ECHO_C" >&6 +if test "${ac_cv_search_opendir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_func_search_save_LIBS=$LIBS +ac_cv_search_opendir=no +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char opendir (); +int +main () +{ +opendir (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_opendir="none required" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test "$ac_cv_search_opendir" = no; then + for ac_lib in x; do + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char opendir (); +int +main () +{ +opendir (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_opendir="-l$ac_lib" +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done +fi +LIBS=$ac_func_search_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_search_opendir" >&5 +echo "${ECHO_T}$ac_cv_search_opendir" >&6 +if test "$ac_cv_search_opendir" != no; then + test "$ac_cv_search_opendir" = "none required" || LIBS="$ac_cv_search_opendir $LIBS" + +fi + +fi + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + + + +for ac_header in fcntl.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------ ## +## Report this to the AC_PACKAGE_NAME lists. ## +## ------------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 +if test "${ac_cv_c_const+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset x; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *ccp; + char **p; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + ccp = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++ccp; + p = (char**) ccp; + ccp = (char const *const *) p; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + } +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_const=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_c_const=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +echo "${ECHO_T}$ac_cv_c_const" >&6 +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\_ACEOF +#define const +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for size_t" >&5 +echo $ECHO_N "checking for size_t... $ECHO_C" >&6 +if test "${ac_cv_type_size_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((size_t *) 0) + return 0; +if (sizeof (size_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_size_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_size_t=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5 +echo "${ECHO_T}$ac_cv_type_size_t" >&6 +if test $ac_cv_type_size_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned +_ACEOF + +fi + +echo "$as_me:$LINENO: checking whether struct tm is in sys/time.h or time.h" >&5 +echo $ECHO_N "checking whether struct tm is in sys/time.h or time.h... $ECHO_C" >&6 +if test "${ac_cv_struct_tm+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +struct tm *tp; tp->tm_sec; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_struct_tm=time.h +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_struct_tm=sys/time.h +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_struct_tm" >&5 +echo "${ECHO_T}$ac_cv_struct_tm" >&6 +if test $ac_cv_struct_tm = sys/time.h; then + +cat >>confdefs.h <<\_ACEOF +#define TM_IN_SYS_TIME 1 +_ACEOF + +fi + + + +for ac_func in vprintf +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +echo "$as_me:$LINENO: checking for _doprnt" >&5 +echo $ECHO_N "checking for _doprnt... $ECHO_C" >&6 +if test "${ac_cv_func__doprnt+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define _doprnt to an innocuous variant, in case declares _doprnt. + For example, HP-UX 11i declares gettimeofday. */ +#define _doprnt innocuous__doprnt + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char _doprnt (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef _doprnt + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char _doprnt (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub__doprnt) || defined (__stub____doprnt) +choke me +#else +char (*f) () = _doprnt; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != _doprnt; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func__doprnt=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func__doprnt=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func__doprnt" >&5 +echo "${ECHO_T}$ac_cv_func__doprnt" >&6 +if test $ac_cv_func__doprnt = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DOPRNT 1 +_ACEOF + +fi + +fi +done + + + + +for ac_func in socket strerror +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +echo "$as_me:$LINENO: checking kernel source directory" >&5 +echo $ECHO_N "checking kernel source directory... $ECHO_C" >&6 +KSRC="/lib/modules/`uname -r`/build" + +# Check whether --with-kernel or --without-kernel was given. +if test "${with_kernel+set}" = set; then + withval="$with_kernel" + KSRC="$withval" +fi; +# Check if kernel source directory has been configured +if test -f "$KSRC/include/linux/version.h" ; then + # Get kernel version number + eval KVER=$(echo "#include " | cpp -I "$KSRC/include" -dM - | awk '/UTS_RELEASE/ { print $3 }') + echo "$as_me:$LINENO: result: $KVER" >&5 +echo "${ECHO_T}$KVER" >&6 +else + echo "$as_me:$LINENO: result: $KSRC/include/linux/version.h not found" >&5 +echo "${ECHO_T}$KSRC/include/linux/version.h not found" >&6 + { { echo "$as_me:$LINENO: error: kernel source directory not specified or not configured" >&5 +echo "$as_me: error: kernel source directory not specified or not configured" >&2;} + { (exit 1); exit 1; }; } +fi + + + + +# Check whether --with-proper or --without-proper was given. +if test "${with_proper+set}" = set; then + withval="$with_proper" + CPPFLAGS="$CPPFLAGS -I$withval/include" ; LDFLAGS="$LDFLAGS -L$withval/.libs" +fi; +if test "${ac_cv_header_prop_h+set}" = set; then + echo "$as_me:$LINENO: checking for prop.h" >&5 +echo $ECHO_N "checking for prop.h... $ECHO_C" >&6 +if test "${ac_cv_header_prop_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_prop_h" >&5 +echo "${ECHO_T}$ac_cv_header_prop_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking prop.h usability" >&5 +echo $ECHO_N "checking prop.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking prop.h presence" >&5 +echo $ECHO_N "checking prop.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: prop.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: prop.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: prop.h: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: prop.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: prop.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: prop.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: prop.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: prop.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: prop.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: prop.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: prop.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: prop.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: prop.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: prop.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: prop.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: prop.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------ ## +## Report this to the AC_PACKAGE_NAME lists. ## +## ------------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for prop.h" >&5 +echo $ECHO_N "checking for prop.h... $ECHO_C" >&6 +if test "${ac_cv_header_prop_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_prop_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_prop_h" >&5 +echo "${ECHO_T}$ac_cv_header_prop_h" >&6 + +fi +if test $ac_cv_header_prop_h = yes; then + HAVE_PROP_H=true +fi + + + +echo "$as_me:$LINENO: checking for prop_create_socket in -lproper" >&5 +echo $ECHO_N "checking for prop_create_socket in -lproper... $ECHO_C" >&6 +if test "${ac_cv_lib_proper_prop_create_socket+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lproper $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char prop_create_socket (); +int +main () +{ +prop_create_socket (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_proper_prop_create_socket=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_proper_prop_create_socket=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_proper_prop_create_socket" >&5 +echo "${ECHO_T}$ac_cv_lib_proper_prop_create_socket" >&6 +if test $ac_cv_lib_proper_prop_create_socket = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBPROPER 1 +_ACEOF + + LIBS="-lproper $LIBS" + +fi + +if test "${ac_cv_header_pthread_h+set}" = set; then + echo "$as_me:$LINENO: checking for pthread.h" >&5 +echo $ECHO_N "checking for pthread.h... $ECHO_C" >&6 +if test "${ac_cv_header_pthread_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_pthread_h" >&5 +echo "${ECHO_T}$ac_cv_header_pthread_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking pthread.h usability" >&5 +echo $ECHO_N "checking pthread.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking pthread.h presence" >&5 +echo $ECHO_N "checking pthread.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: pthread.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: pthread.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: pthread.h: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: pthread.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: pthread.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: pthread.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: pthread.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: pthread.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: pthread.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: pthread.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: pthread.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: pthread.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: pthread.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: pthread.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: pthread.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: pthread.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------ ## +## Report this to the AC_PACKAGE_NAME lists. ## +## ------------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for pthread.h" >&5 +echo $ECHO_N "checking for pthread.h... $ECHO_C" >&6 +if test "${ac_cv_header_pthread_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_pthread_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_pthread_h" >&5 +echo "${ECHO_T}$ac_cv_header_pthread_h" >&6 + +fi +if test $ac_cv_header_pthread_h = yes; then + HAVE_PTHREAD_H=true +else + { { echo "$as_me:$LINENO: error: NetFlow requires pthread" >&5 +echo "$as_me: error: NetFlow requires pthread" >&2;} + { (exit 1); exit 1; }; } +fi + + + +echo "$as_me:$LINENO: checking for pthread_create in -lpthread" >&5 +echo $ECHO_N "checking for pthread_create in -lpthread... $ECHO_C" >&6 +if test "${ac_cv_lib_pthread_pthread_create+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char pthread_create (); +int +main () +{ +pthread_create (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_pthread_pthread_create=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_pthread_pthread_create=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_pthread_pthread_create" >&5 +echo "${ECHO_T}$ac_cv_lib_pthread_pthread_create" >&6 +if test $ac_cv_lib_pthread_pthread_create = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBPTHREAD 1 +_ACEOF + + LIBS="-lpthread $LIBS" + +else + { { echo "$as_me:$LINENO: error: NetFlow requires pthread" >&5 +echo "$as_me: error: NetFlow requires pthread" >&2;} + { (exit 1); exit 1; }; } +fi + + +DATABASE_DIR="" +DATABASE_LIB="" +DATABASE_LIB_DIR="" + +DATABASE_DRIVERS="" + + +# Check whether --with-mysql or --without-mysql was given. +if test "${with_mysql+set}" = set; then + withval="$with_mysql" + +if test $withval != yes +then + dir=$withval +else + dir="/usr/local" +fi +mysqldir="" +echo "$as_me:$LINENO: checking for MySQL files" >&5 +echo $ECHO_N "checking for MySQL files... $ECHO_C" >&6 +for d in $dir /usr /usr/local /usr/local/mysql /opt/mysql /opt/packages/mysql +do + if test -f $d/lib/mysql/libmysqlclient.so + then + echo "$as_me:$LINENO: result: found mysql in $d" >&5 +echo "${ECHO_T}found mysql in $d" >&6 + mysqldir=$d + MYSQLINCLUDES=${mysqldir}/include/mysql + MYSQLLIBS=${mysqldir}/lib/mysql + break + elif test -f $d/lib/libmysqlclient.so + then + echo "$as_me:$LINENO: result: found mysql in $d" >&5 +echo "${ECHO_T}found mysql in $d" >&6 + mysqldir=$d + MYSQLINCLUDES=${mysqldir}/include + MYSQLLIBS=${mysqldir}/lib + break + elif test -f $d/libmysql/.libs/libmysqlclient.so + then + echo "$as_me:$LINENO: result: found mysql in $d" >&5 +echo "${ECHO_T}found mysql in $d" >&6 + mysqldir=$d + ln -nsf ${mysqldir}/include include/mysql + MYSQLINCLUDES=$PWD/include + MYSQLLIBS=${mysqldir}/libmysql/.libs + break + fi +done + +if test x$mysqldir = x +then + { echo "$as_me:$LINENO: WARNING: MySQL backend not used" >&5 +echo "$as_me: WARNING: MySQL backend not used" >&2;} +else + cat >>confdefs.h <<\_ACEOF +#define HAVE_MYSQL 1 +_ACEOF + + + DATABASE_DIR="${DATABASE_DIR} mysql" + + MYSQL_LIB="${DATABASE_LIB} -lmysqlclient " + DATABASE_LIB_DIR="${DATABASE_LIB_DIR} -L${MYSQLLIBS} " + + DATABASE_DRIVERS="${DATABASE_DRIVERS} ../mysql/mysql_driver.o " + + DB_DEF="${DB_DEF} -DHAVE_MYSQL " + + + + + + if test -f $MYSQLLIBS/libmystrings.so + then + DATABASE_LIB="${DATABASE_LIB} -lmystrings " + else + MYSQLEXTRALIBS= + fi + + + echo "$as_me:$LINENO: checking for mysql_real_escape_string support" >&5 +echo $ECHO_N "checking for mysql_real_escape_string support... $ECHO_C" >&6 + + MYSQL_FUNCTION_TEST=`strings ${MYSQLLIBS}/libmysqlclient.so | grep mysql_real_escape_string` + + if test "x$MYSQL_FUNCTION_TEST" = x + then + EXTRA_MYSQL_DEF="OLD_MYSQL=1 " + echo "$as_me:$LINENO: result: found old MySQL" >&5 +echo "${ECHO_T}found old MySQL" >&6 + else + echo "$as_me:$LINENO: result: found new MySQL" >&5 +echo "${ECHO_T}found new MySQL" >&6 + fi + +fi + +fi; + + + + +# Check whether --with-mysql-log-ip-as-string or --without-mysql-log-ip-as-string was given. +if test "${with_mysql_log_ip_as_string+set}" = set; then + withval="$with_mysql_log_ip_as_string" + + EXTRA_MYSQL_DEF="-D${EXTRA_MYSQL_DEF} -DIP_AS_STRING=1" + { echo "$as_me:$LINENO: WARNING: the use of --with-mysql-log-ip-as-string is discouraged" >&5 +echo "$as_me: WARNING: the use of --with-mysql-log-ip-as-string is discouraged" >&2;} + +fi; + + + +# Check whether --with-pgsql or --without-pgsql was given. +if test "${with_pgsql+set}" = set; then + withval="$with_pgsql" + +if test $withval != yes +then + dir=$withval +else + dir="/usr/local" +fi +pgsqldir="" +echo "$as_me:$LINENO: checking for PGSQL files" >&5 +echo $ECHO_N "checking for PGSQL files... $ECHO_C" >&6 +for d in $dir /usr /usr/local /usr/local/pgsql /opt/pgsql /opt/packages/pgsql +do + if test -f $d/lib/pgsql/libpq.so + then + echo "$as_me:$LINENO: result: found pgsql in $d" >&5 +echo "${ECHO_T}found pgsql in $d" >&6 + pgsqldir=$d + break + elif test -f $d/lib/libpq.so + then + echo "$as_me:$LINENO: result: found pgsql in $d" >&5 +echo "${ECHO_T}found pgsql in $d" >&6 + pgsqldir=$d + break + fi +done + +if test x$pgsqldir = x +then + { echo "$as_me:$LINENO: WARNING: PGSQL backend not used" >&5 +echo "$as_me: WARNING: PGSQL backend not used" >&2;} +else + cat >>confdefs.h <<\_ACEOF +#define HAVE_PGSQL 1 +_ACEOF + + for i in include include/postgresql include/pgsql + do + if test -f ${pgsqldir}/$i/libpq-fe.h + then + PGSQLINCLUDES=${pgsqldir}/$i + break + fi + done + PGSQLLIBS=${pgsqldir}/lib + + DATABASE_DIR="${DATABASE_DIR} pgsql" + + PGSQL_LIB="${DATABASE_LIB} -lpq " + DATABASE_LIB_DIR="${DATABASE_LIB_DIR} -L${PGSQLLIBS} " + + DB_DEF="${DB_DEF} -DHAVE_PGSQL " + + + + +fi + +fi; + + + +# Check whether --with-pgsql-log-ip-as-string or --without-pgsql-log-ip-as-string was given. +if test "${with_pgsql_log_ip_as_string+set}" = set; then + withval="$with_pgsql_log_ip_as_string" + + EXTRA_PGSQL_DEF="-DIP_AS_STRING=1" + +fi; + + + + + + + + + + + + + + + + +if test x$mysqldir != x; then + HAVE_MYSQL_TRUE= + HAVE_MYSQL_FALSE='#' +else + HAVE_MYSQL_TRUE='#' + HAVE_MYSQL_FALSE= +fi + + +if test x$pgsqldir != x; then + HAVE_PGSQL_TRUE= + HAVE_PGSQL_FALSE='#' +else + HAVE_PGSQL_TRUE='#' + HAVE_PGSQL_FALSE= +fi + + ac_config_files="$ac_config_files extensions/Makefile doc/Makefile conffile/Makefile libipulog/Makefile mysql/Makefile pgsql/Makefile pcap/Makefile netflow/Makefile Makefile Rules.make" +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then we branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +cat >confdef2opt.sed <<\_ACEOF +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g +t quote +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g +t quote +d +: quote +s,[ `~#$^&*(){}\\|;'"<>?],\\&,g +s,\[,\\&,g +s,\],\\&,g +s,\$,$$,g +p +_ACEOF +# We use echo to avoid assuming a particular line-breaking character. +# The extra dot is to prevent the shell from consuming trailing +# line-breaks from the sub-command output. A line-break within +# single-quotes doesn't work because, if this script is created in a +# platform that uses two characters for line-breaks (e.g., DOS), tr +# would break. +ac_LF_and_DOT=`echo; echo .` +DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'` +rm -f confdef2opt.sed + + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_i=`echo "$ac_i" | + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + # 2. Add them. + ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by $as_me, which was +generated by GNU Autoconf 2.59. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Report bugs to ." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.59, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2003 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +INSTALL="$INSTALL" +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + ac_shift=: + ;; + -*) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_option=$1 + ac_need_defaults=false;; + esac + + case $ac_option in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF + + + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "extensions/Makefile" ) CONFIG_FILES="$CONFIG_FILES extensions/Makefile" ;; + "doc/Makefile" ) CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; + "conffile/Makefile" ) CONFIG_FILES="$CONFIG_FILES conffile/Makefile" ;; + "libipulog/Makefile" ) CONFIG_FILES="$CONFIG_FILES libipulog/Makefile" ;; + "mysql/Makefile" ) CONFIG_FILES="$CONFIG_FILES mysql/Makefile" ;; + "pgsql/Makefile" ) CONFIG_FILES="$CONFIG_FILES pgsql/Makefile" ;; + "pcap/Makefile" ) CONFIG_FILES="$CONFIG_FILES pcap/Makefile" ;; + "netflow/Makefile" ) CONFIG_FILES="$CONFIG_FILES netflow/Makefile" ;; + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "Rules.make" ) CONFIG_FILES="$CONFIG_FILES Rules.make" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./confstat$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@SET_MAKE@,$SET_MAKE,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@LD@,$LD,;t t +s,@ac_ct_LD@,$ac_ct_LD,;t t +s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t +s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t +s,@INSTALL_DATA@,$INSTALL_DATA,;t t +s,@CPP@,$CPP,;t t +s,@EGREP@,$EGREP,;t t +s,@KSRC@,$KSRC,;t t +s,@KVER@,$KVER,;t t +s,@MYSQLINCLUDES@,$MYSQLINCLUDES,;t t +s,@MYSQL_LIB@,$MYSQL_LIB,;t t +s,@PGSQLINCLUDES@,$PGSQLINCLUDES,;t t +s,@PGSQL_LIB@,$PGSQL_LIB,;t t +s,@DATABASE_DIR@,$DATABASE_DIR,;t t +s,@DATABASE_LIB@,$DATABASE_LIB,;t t +s,@DATABASE_LIB_DIR@,$DATABASE_LIB_DIR,;t t +s,@DB_DEF@,$DB_DEF,;t t +s,@EXTRA_MYSQL_DEF@,$EXTRA_MYSQL_DEF,;t t +s,@EXTRA_PGSQL_DEF@,$EXTRA_PGSQL_DEF,;t t +s,@DATABASE_DRIVERS@,$DATABASE_DRIVERS,;t t +s,@HAVE_PCAP_H@,$HAVE_PCAP_H,;t t +s,@HAVE_MYSQL_TRUE@,$HAVE_MYSQL_TRUE,;t t +s,@HAVE_MYSQL_FALSE@,$HAVE_MYSQL_FALSE,;t t +s,@HAVE_PGSQL_TRUE@,$HAVE_PGSQL_TRUE,;t t +s,@HAVE_PGSQL_FALSE@,$HAVE_PGSQL_FALSE,;t t +s,@LIBOBJS@,$LIBOBJS,;t t +s,@LTLIBOBJS@,$LTLIBOBJS,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_builddir$INSTALL ;; + esac + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +s,@INSTALL@,$ac_INSTALL,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..7504e21 --- /dev/null +++ b/configure.in @@ -0,0 +1,298 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(ulogd.c) + +dnl Checks for programs. +AC_PROG_MAKE_SET +AC_PROG_CC +AC_CHECK_TOOL(LD, ld) +AC_PROG_INSTALL + +dnl Checks for libraries. +AC_CHECK_LIB(dl, dlopen) +AC_CHECK_HEADER(pcap.h,HAVE_PCAP_H=true) + +dnl Checks for header files. +AC_HEADER_DIRENT +AC_HEADER_STDC +AC_CHECK_HEADERS(fcntl.h unistd.h) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_SIZE_T +AC_STRUCT_TM + +dnl Checks for library functions. +AC_FUNC_VPRINTF +AC_CHECK_FUNCS(socket strerror) + +dnl Checks for kernel source directory. +AC_MSG_CHECKING([kernel source directory]) +KSRC="/lib/modules/`uname -r`/build" +AC_ARG_WITH(kernel, + --with-kernel=DIR kernel source directory, + [ KSRC="$withval" ], +) +# Check if kernel source directory has been configured +if test -f "$KSRC/include/linux/version.h" ; then + # Get kernel version number + eval KVER=$(echo "#include " | cpp -I "$KSRC/include" -dM - | awk '/UTS_RELEASE/ { print $3 }') + AC_MSG_RESULT([$KVER]) +else + AC_MSG_RESULT([$KSRC/include/linux/version.h not found]) + AC_MSG_ERROR(kernel source directory not specified or not configured) +fi +AC_SUBST(KSRC) +AC_SUBST(KVER) + +dnl NetFlow prerequisites. +AC_ARG_WITH(proper, + --with-proper= proper installed in , + [ CPPFLAGS="$CPPFLAGS -I$withval/include" ; LDFLAGS="$LDFLAGS -L$withval/.libs" ], +) +AC_CHECK_HEADER(prop.h, HAVE_PROP_H=true) +AC_CHECK_LIB(proper, prop_create_socket) +AC_CHECK_HEADER(pthread.h, HAVE_PTHREAD_H=true, AC_MSG_ERROR(NetFlow requires pthread)) +AC_CHECK_LIB(pthread, pthread_create, [], AC_MSG_ERROR(NetFlow requires pthread)) + +DATABASE_DIR="" +DATABASE_LIB="" +DATABASE_LIB_DIR="" + +DATABASE_DRIVERS="" + +dnl +dnl test for MySQL +dnl +AC_ARG_WITH(mysql, + --with-mysql= mysql installed in ,[ +if test $withval != yes +then + dir=$withval +else + dir="/usr/local" +fi +mysqldir="" +AC_MSG_CHECKING(for MySQL files) +for d in $dir/bin /usr/bin /usr/local/bin /usr/local/mysql/bin /opt/mysql/bin /opt/packages/mysql/bin +do + if test -f $d/mysql_config + then + AC_MSG_RESULT(found mysql_config in $d) + mysqldir=$d + break + fi +done + +if test x$mysqldir = x +then + AC_MSG_WARN(MySQL backend not used) +else + AC_DEFINE(HAVE_MYSQL) + MYSQLINCLUDES=`$d/mysql_config --include` + MYSQLLIBS=`$d/mysql_config --libs` + + DATABASE_DIR="${DATABASE_DIR} mysql" + + MYSQL_LIB="${DATABASE_LIB} ${MYSQLLIBS} " + # no change to DATABASE_LIB_DIR, since --libs already includes -L + + DATABASE_DRIVERS="${DATABASE_DRIVERS} ../mysql/mysql_driver.o " + + DB_DEF="${DB_DEF} -DHAVE_MYSQL " + + + AC_SUBST(MYSQLINCLUDES) + AC_SUBST(MYSQL_LIB) + + dnl Here we check whether we have an old MySQL client library + dnl installed, which does not support the mysql_real_escape_string(), + dnl but the real_escape_string() function. + dnl Having a look in the libary itself should be more reliable than + dnl parsing the output of mysql --version. + + AC_MSG_CHECKING(for mysql_real_escape_string support) + + MYSQL_FUNCTION_TEST=`strings ${MYSQLLIBS}/libmysqlclient.so | grep mysql_real_escape_string` + + if test "x$MYSQL_FUNCTION_TEST" = x + then + EXTRA_MYSQL_DEF="-DOLD_MYSQL=1 " + AC_MSG_RESULT(found old MySQL) + else + AC_MSG_RESULT(found new MySQL) + fi + +fi +]) + + +dnl +dnl Check whether the user wants log IP-addresses as strings rather +dnl than as unsigned long-integers to his MySQL-database. Since this +dnl feature is only used in ulogd_MYSQL.c, there are no checks in any +dnl way. +dnl + +AC_ARG_WITH(mysql-log-ip-as-string, + --with-mysql-log-ip-as-string log IPs as string rather than as + unsigned long-integer. +,[ + EXTRA_MYSQL_DEF="${EXTRA_MYSQL_DEF} -DIP_AS_STRING=1" + AC_MSG_WARN(the use of --with-mysql-log-ip-as-string is discouraged) +]) + + +dnl +dnl test for PostgreSQL +dnl +AC_ARG_WITH(pgsql, + --with-pgsql= pgsql installed in ,[ +if test $withval != yes +then + dir=$withval +else + dir="/usr/local" +fi +pgsqldir="" +AC_MSG_CHECKING(for PGSQL files) +for d in $dir/bin /usr/bin /usr/local/bin /usr/local/pgsql/bin /opt/pgsql/bin /opt/packages/pgsql/bin +do + if test -x $d/pg_config + then + AC_MSG_RESULT(found pg_config in $d) + pgsqldir=$d + break + fi +done + +if test x$pgsqldir = x +then + AC_MSG_WARN(PGSQL backend not used) +else + AC_DEFINE(HAVE_PGSQL) + PGSQLINCLUDES=`$pgsqldir/pg_config --includedir` + PGSQLLIBS=`$pgsqldir/pg_config --libdir` + + DATABASE_DIR="${DATABASE_DIR} pgsql" + PGSQL_LIB="${DATABASE_LIB} -lpq " + + DATABASE_LIB_DIR="${DATABASE_LIB_DIR} -L${PGSQLLIBS} " + DB_DEF="${DB_DEF} -DHAVE_PGSQL " + + AC_SUBST(PGSQLINCLUDES) + AC_SUBST(PGSQL_LIB) + +fi +]) + +dnl +dnl Check whether the user wants to log IP-addresses as strings rather +dnl than integers to his pgsql-database. +dnl + +AC_ARG_WITH(pgsql-log-ip-as-string, + --with-pgsql-log-ip-as-string log IPs as string rather than as interger +,[ + EXTRA_PGSQL_DEF="-DIP_AS_STRING=1" +]) + + +dnl +dnl test for sqlite3 +dnl +AC_ARG_WITH(sqlite3, + --with-sqlite3= sqlite3 installed in ,[ +if test $withval != yes +then + dir=$withval +else + dir="/usr/local" +fi +mysqldir="" +AC_MSG_CHECKING(for sqlite3 files) +for d in $dir /usr /usr/local /usr/local/sqlite3 +do + if test -f $d/lib/sqlite3/libsqlite3.so + then + AC_MSG_RESULT(found sqlite3 in $d) + sqlite3dir=$d + sqlite3dir_suffix=/sqlite3 + break + elif test -f $d/lib64/sqlite3/libsqlite3.so + then + AC_MSG_RESULT(found sqlite3 in $d) + sqlite3dir=$d + sqlite3dir_suffix=/sqlite3 + break + elif test -f $d/lib/libsqlite3.so + then + AC_MSG_RESULT(found sqlite in $d) + sqlite3dir=$d + sqlite3dir_suffix= + break + elif test -f $d/lib64/libsqlite3.so + then + AC_MSG_RESULT(found sqlite in $d) + sqlite3dir=$d + sqlite3dir_suffix= + break + fi +done + +if test x$sqlite3dir = x +then + AC_MSG_WARN(sqlite3 backend not used) +else + AC_DEFINE(HAVE_SQLITE3) + SQLITE3INCLUDES=${sqlite3dir}/include${sqlite3dir_suffix} + SQLITE3LIBS=${sqlite3dir}/lib${sqlite3dir_suffix} + + DATABASE_DIR="${DATABASE_DIR} sqlite3" + + SQLITE3_LIB="${DATABASE_LIB} -lsqlite3 " + DATABASE_LIB_DIR="${DATABASE_LIB_DIR} -L${SQLITE3LIBS} " + +dnl DATABASE_DRIVERS="${DATABASE_DRIVERS} ../sqlite3/mysql_driver.o " + + DB_DEF="${DB_DEF} -DHAVE_SQLITE3 " + + + AC_SUBST(SQLITE3INCLUDES) + AC_SUBST(SQLITE3_LIB) + +fi +]) + + +dnl +dnl Check whether the user wants log IP-addresses as strings rather +dnl than as unsigned long-integers to his sqlite3-database. Since this +dnl feature is only used in ulogd_SQLITE3.c, there are no checks in any +dnl way. +dnl + +AC_ARG_WITH(sqlite3-log-ip-as-string, + --with-sqlite3-log-ip-as-string log IPs as string rather than as + unsigned long-integer. +,[ + EXTRA_SQLITE3_DEF="${EXTRA_SQLITE3_DEF} -DIP_AS_STRING=1" + AC_MSG_WARN(the use of --with-sqlite3-log-ip-as-string is discouraged) +]) + + +AC_SUBST(DATABASE_DIR) +AC_SUBST(DATABASE_LIB) +AC_SUBST(DATABASE_LIB_DIR) +AC_SUBST(DB_DEF) +AC_SUBST(EXTRA_MYSQL_DEF) +AC_SUBST(EXTRA_PGSQL_DEF) +AC_SUBST(EXTRA_SQLITE3_DEF) + +AC_SUBST(DATABASE_DRIVERS) +AC_SUBST(HAVE_PCAP_H) + +AM_CONDITIONAL(HAVE_MYSQL, test x$mysqldir != x) +AM_CONDITIONAL(HAVE_PGSQL, test x$pgsqldir != x) +AM_CONDITIONAL(HAVE_SQLITE3, test x$sqlite3dir != x) + +AC_OUTPUT(extensions/Makefile doc/Makefile conffile/Makefile libipulog/Makefile mysql/Makefile pgsql/Makefile sqlite3/Makefile pcap/Makefile drl/Makefile Makefile Rules.make) diff --git a/contrib/ulog_query.php.gz b/contrib/ulog_query.php.gz new file mode 100644 index 0000000000000000000000000000000000000000..e57bc0b177b48fbdc2e076a87e566361e5944817 GIT binary patch literal 2875 zcmV-B3&ivviwFpQr29Mo19fa~XJ2u3Wpa5gaAiB-JdXDEPRaCWdW@naTl1(5 zKPB(ti2PavTk?_||LgSc)6?mcyt@2APNvfng!yr@P5FA0H({e!V^M`Hx8yw!GIF&E zLdIE&7#4aw=&GXZD+}V}-?6NE6sPO`r*UQJ&nG2&Hqbk}eM+tm8=jFQjn}Cc5_nvt zjFBu}<@a97&d4?{i0?%tWt3-m%9lmX2+xTZ(Mg<=Fs6L9t++s5M3ki@-!PK1G|Wi6 z5NbwN92=67I6?RrtlyHr%WH-sYkxhN@1N!aBkg>DZ?<6`h3~yt z&hvnse}rL5z*pYV0}qSwI-8V5PW~zKQAFN#ZPb zusW!FdHx$#I0dekLUf(76@NG-Gae;HPV#NS=1$HYa)(4-2+wi6TqL5Bb3RK1<`+?w zN6-%|&u5Q-c~mODD)L=magi&9*J+%`ejJbymSc=WMYv??cz}Z^V0H;pJU0+aJ|n+e z6OYoAW!W%3!&;^B7c9$pB!bu)PD{Ad{o&O$3{RmyiPL-ln){#{>o^KXHT4!~TB4=q zj~BL@3);|(z#TLrx~VyY6#}ApsH>sM0;`l7L+{~HfcGE)QV9n24GWkU1$AII2>cE6 z@0RgHMdB~KAaKZ6FDNkFAVO!$a}doYOL$5x2^J8iJtQbbA`21>^qhxmkukr)q!;YM zQy7T~dnP&D8#K#GY{?ON>0QSV6k6h8)@Y-7WQoP8qYVbx4js#rzJBG2Ww)xiLno<( zc6i!{r}lU?_q8Z0xgAR$XKexySz_~!auC_-g(WZQsz#|D1K)JCgUAl+XGPcsqs&q> z?I@;p$W`jC9PNSrj478Vl?!b_-FI@}R7fZC~-}Moc zVoQ#D9?|%|!%>PYIf``MApn^@I_ZNa_Fm|7fh9W0HXSs`EYWG!?SGKj_Wm~N_Wssp z0>GLp-bI6KhhYR8n!aHKV#{Gv@27McCADPe4kIPCWN6Q&Qnt&2=!gAFBFJqQMX0*K z!sh%|No^VYnD#KB)Ruwyo47qm*YaIh+OvyZV9T?Hz3jcW?efS1TOM2`!o2A6$bwzA zwRlGF-PmG*ZFjdkY~$F}yN5kua|0`77U<+Yi}-4VJKd)Bdch7niI-))JXm1k$_>kK zr1J)el4{47D{;M%Ssq?!)HDmuqbbAt5GE?Xk1P%fabg?c6%dd7l;M2>?EQQ=weo09 z@JK*t>VHsCYUS9o>C+qfQbC`{(_Xyu12KO zwC#N(ECBbk*&J*9e)V75a6E~8ujPR4suqN{wp%jvTCX1=R0|F(DO%iD@k}-JfM?*R ze54>_2nY?nX1RD=ZZT%HYG=FpN;6GZ!iJ zT%Srb&S8sf;YQ2p|71DsRZVRzw}JOsUT^)s$8v>ksMa`#Ew_amE&qO>D|AP-mCtSA zy_T!H?AK=(VXx=*)vT8(HpO^W|NPMhh?mX_E%Z2(<5t?jik zfuOq#6A(!I%#|y&uC@aese?~-3v0Y?mfN_!ckA73v$T{FP z-Jn}inb1WCE}xE^rqyO1?WoXCA{%RF5LpH@UU2%ERPP8w_w%H; z_Z3aG>v5|E-_`c3Zg~ywmN)9Ix*2!NOKw+QSBsz2t#6QRqC?+D4%yZ38-3r^kEX+D z{mju%pqyajz@&u{j(#&E^8v-^>H(c1VKJaqbdV8`=?Wtl`_zaO$qFM>#DQ5W9Z*Wm zxGGU$1h)guFbc#;XlNLyZKA8TU9QXlxb;=OTi?jL@^ZZTPO56IytsDd6|^falU;c& zY%?|*`{+Sy`#sm#%^L9Z5jx@Pi&+pe7Q@Pn#TyD~0s?T|N&PI2WhG&?I9!#faJ77ct0xUy{pR1* zukWqaZk1s%Ow7s>!_2PoD+738{{UWQR|XhlyC2~&&r}VE4X{+1l>wH@(*rD3US)u# z-9@G?zeuYL#|m|2zQfg%7OtLoa8(AuDkh9wVd{Y@3DXa&%R*>R(x&!nCFu^5Xa#oPDJS4#nG}coMw1e0%xo196U&yU6R` zuilCG$er#%T><3-p3whzbNTxvsqZPz_9qj{mc@FF38+}S4SGs&91{nVljS>nr&R|z zgY^^n9;;M{_^J&l%ZeaZog&IdWwoZ$5LCl&jGjwU9_64DTpTd6j8n?e`K@z&>zv=> zb$qE7jwD5xDYa1%!Wzp0nvJAI)n$n|KP@ora7gP%ajYpH<>`6;;`mJ0f1A&8@dEHH zPfNvExPsP<4*7g~Mh-cd5orhhdj7ngYJ_wl(u0+S!n#G7eJL$;0VJ)gm7-eE`Q~ru z8p&(|zh@IDP==K8P*<62uh1$xwAN#=a0x9ZuwDY%CZIbKs1v2ep`2~Q(YP(jAj&`&%ph8yu-xA)yfpQ;b*H@h&&_Xd7chlfy&5b1T2N@w zuy^bP!*Xz}N{io3c*b!iD9=VUsriol8fU3K4wUn7U! z9)-6@+gtMH_LSeAW_V>->pQEE=;dCPsjAWnK2@m|ae9|w1M1j22PwR2Pkn zZB|ttX|#%Et%-*{Syu7Fd~XXn-bO^f)>=gyq&1 | sed "s?^:\([0-9]*\):[^ ]* ?$<:\1:?" + +%.a4.dvi: %.sgml + @echo Making $@: && cd `dirname $<` && sgml2latex --papersize=a4 --output=dvi $(HOWTO_FLAGS_$(dir $<)) `basename $<` 2>&1 | sed "s?^:\([0-9]*\):[^ ]* ?$<:\1:?" && mv `basename $*.dvi` `basename $*.a4.dvi` + +%.a4.ps: %.a4.dvi + @dvips -t a4 -o $@ $< + +%.letter.dvi: %.sgml + @echo Making $@: && cd `dirname $<` && sgml2latex --papersize=letter --output=dvi $(HOWTO_FLAGS_$(dir $<)) `basename $<` 2>&1 | sed "s?^:\([0-9]*\):[^ ]* ?$<:\1:?" && mv `basename $*.dvi` `basename $*.letter.dvi` + +%.letter.ps: %.letter.dvi + @dvips -t letter -o $@ $< + +%.html: %.sgml + @echo Making $@: && cd `dirname $<` && sgml2html -s 0 $(HOWTO_FLAGS_$(dir $<)) `basename $<` 2>&1 | sed "s?^:\([0-9]*\):[^ ]* ?$<:\1:?" + +clean: +# for d in . $(LANG_DIRS); do rm -f $$d/*.html $$d/*.ps $$d/*.aux $$d/*.log $$d/*.txt $$d/*~; done + +distclean: + rm -f Makefile + +install: diff --git a/doc/mysql.table b/doc/mysql.table new file mode 100644 index 0000000..bdfee71 --- /dev/null +++ b/doc/mysql.table @@ -0,0 +1,55 @@ +CREATE TABLE ulog ( id INT UNSIGNED AUTO_INCREMENT UNIQUE, + + raw_mac VARCHAR(80), + + oob_time_sec INT UNSIGNED, + oob_time_usec INT UNSIGNED, + oob_prefix VARCHAR(32), + oob_mark INT UNSIGNED, + oob_in VARCHAR(32), + oob_out VARCHAR(32), + + ip_saddr INT UNSIGNED, + ip_daddr INT UNSIGNED, + ip_protocol TINYINT UNSIGNED, + ip_tos TINYINT UNSIGNED, + ip_ttl TINYINT UNSIGNED, + ip_totlen SMALLINT UNSIGNED, + ip_ihl TINYINT UNSIGNED, + ip_csum SMALLINT UNSIGNED, + ip_id SMALLINT UNSIGNED, + ip_fragoff SMALLINT UNSIGNED, + + tcp_sport SMALLINT UNSIGNED, + tcp_dport SMALLINT UNSIGNED, + tcp_seq INT UNSIGNED, + tcp_ackseq INT UNSIGNED, + tcp_window SMALLINT UNSIGNED, + tcp_urg TINYINT, + tcp_urgp SMALLINT UNSIGNED, + tcp_ack TINYINT, + tcp_psh TINYINT, + tcp_rst TINYINT, + tcp_syn TINYINT, + tcp_fin TINYINT, + + udp_sport SMALLINT UNSIGNED, + udp_dport SMALLINT UNSIGNED, + udp_len SMALLINT UNSIGNED, + + icmp_type TINYINT UNSIGNED, + icmp_code TINYINT UNSIGNED, + icmp_echoid SMALLINT UNSIGNED, + icmp_echoseq SMALLINT UNSIGNED, + icmp_gateway INT UNSIGNED, + icmp_fragmtu SMALLINT UNSIGNED, + + pwsniff_user VARCHAR(30), + pwsniff_pass VARCHAR(30), + + ahesp_spi INT UNSIGNED, + + KEY index_id (id) + ); + + diff --git a/doc/mysql.table.ipaddr-as-string b/doc/mysql.table.ipaddr-as-string new file mode 100644 index 0000000..c9bd508 --- /dev/null +++ b/doc/mysql.table.ipaddr-as-string @@ -0,0 +1,58 @@ +# MySQL dump 7.1 +# +# Host: localhost Database: ulogd +#-------------------------------------------------------- +# Server version 3.22.32 + +# This table is intended for use with older MySQL-Servers and +# the --with-mysql-log-ip-as-string feature. It will not work +# without that feature. +# +# Table structure for table 'ulog' +# +CREATE TABLE ulog ( + id int(10) unsigned DEFAULT '0' NOT NULL auto_increment, + raw_mac varchar(80), + oob_time_sec int(10) unsigned, + oob_time_usec int(10) unsigned, + oob_prefix varchar(32), + oob_mark int(10) unsigned, + oob_in varchar(32), + oob_out varchar(32), + ip_saddr varchar(16), + ip_daddr varchar(16), + ip_protocol tinyint(3) unsigned, + ip_tos tinyint(3) unsigned, + ip_ttl tinyint(3) unsigned, + ip_totlen smallint(5) unsigned, + ip_ihl tinyint(3) unsigned, + ip_csum smallint(5) unsigned, + ip_id smallint(5) unsigned, + ip_fragoff smallint(5) unsigned, + tcp_sport smallint(5) unsigned, + tcp_dport smallint(5) unsigned, + tcp_seq int(10) unsigned, + tcp_ackseq int(10) unsigned, + tcp_window smallint(5) unsigned, + tcp_urg tinyint(4), + tcp_urgp smallint(5) unsigned, + tcp_ack tinyint(4), + tcp_psh tinyint(4), + tcp_rst tinyint(4), + tcp_syn tinyint(4), + tcp_fin tinyint(4), + udp_sport smallint(5) unsigned, + udp_dport smallint(5) unsigned, + udp_len smallint(5) unsigned, + icmp_type tinyint(3) unsigned, + icmp_code tinyint(3) unsigned, + icmp_echoid smallint(5) unsigned, + icmp_echoseq smallint(5) unsigned, + icmp_gateway int(10) unsigned, + icmp_fragmtu smallint(5) unsigned, + pwsniff_user varchar(30), + pwsniff_pass varchar(30), + ahesp_spi int(10) unsigned, + PRIMARY KEY (id) +); + diff --git a/doc/pgsql.table b/doc/pgsql.table new file mode 100644 index 0000000..193f747 --- /dev/null +++ b/doc/pgsql.table @@ -0,0 +1,81 @@ +/* ulogd.pgsql.table, Version 0.1 + * + * sample of a postgres table for ulogd + * + * All columns except "id" are optional! Comment all unwanted + * columns out, e.g. by prefixing them with '--' + * + * "raw_pkt" is not supported by ulogd_PGSQL + */ + +CREATE SEQUENCE "seq_ulog"; + +CREATE TABLE "ulog" ( + "id" integer DEFAULT nextval('seq_ulog') NOT NULL, + + "oob_prefix" character varying(32), + "oob_time_sec" integer, + "oob_time_usec" integer, + "oob_mark" bigint, + "oob_in" character varying(32), + "oob_out" character varying(32), + + "raw_mac" character varying(80), + "raw_pktlen" bigint, + + "ip_ihl" smallint, + "ip_tos" smallint, + "ip_totlen" integer, + "ip_id" integer, + "ip_fragoff" integer, + "ip_ttl" smallint, + "ip_protocol" smallint, + "ip_csum" integer, + +/* log IPs as unsigned int32 (default) */ + "ip_saddr" bigint, + "ip_daddr" bigint, + +/* log IPs as string (--with-pgsql-log-ip-as-string) */ +-- "ip_saddr" character varying(40), +-- "ip_daddr" character varying(40), + +/* log IPs as inet (--with-pgsql-log-ip-as-string) */ +-- "ip_saddr" inet, +-- "ip_daddr" inet, + + + "tcp_sport" integer, + "tcp_dport" integer, + "tcp_seq" bigint, + "tcp_ackseq" bigint, + "tcp_urg" boolean, + "tcp_ack" boolean, + "tcp_psh" boolean, + "tcp_rst" boolean, + "tcp_syn" boolean, + "tcp_fin" boolean, + "tcp_window" integer, + "tcp_urgp" integer, + + "udp_sport" integer, + "udp_dport" integer, + "udp_len" integer, + + "icmp_type" smallint, + "icmp_code" smallint, + "icmp_echoid" integer, + "icmp_echoseq" integer, + "icmp_gateway" bigint, + "icmp_fragmtu" integer, + + "pwsniff_user" character varying(30), + "pwsniff_pass" character varying(30), + + "ahesp_spi" smallint, + + "local_time" bigint, + "local_hostname" character varying(40) +); + + diff --git a/doc/sqlite3.table b/doc/sqlite3.table new file mode 100644 index 0000000..7b5e99a --- /dev/null +++ b/doc/sqlite3.table @@ -0,0 +1,22 @@ +CREATE TABLE ulog ( + raw_mac VARCHAR(80), + oob_time_sec INT UNSIGNED, + oob_time_usec INT UNSIGNED, + ip_saddr INT UNSIGNED, + ip_daddr INT UNSIGNED, + ip_protocol TINYINT UNSIGNED, + ip_totlen SMALLINT UNSIGNED, + tcp_sport SMALLINT UNSIGNED, + tcp_dport SMALLINT UNSIGNED, + udp_sport SMALLINT UNSIGNED, + udp_dport SMALLINT UNSIGNED, + udp_len SMALLINT UNSIGNED, + icmp_type TINYINT UNSIGNED, + icmp_code TINYINT UNSIGNED, + icmp_echoid SMALLINT UNSIGNED, + icmp_echoseq SMALLINT UNSIGNED, + icmp_gateway INT UNSIGNED, + icmp_fragmtu SMALLINT UNSIGNED + ); + + diff --git a/doc/ulogd.a4.ps b/doc/ulogd.a4.ps new file mode 100644 index 0000000..2e829a7 --- /dev/null +++ b/doc/ulogd.a4.ps @@ -0,0 +1,4025 @@ +%!PS-Adobe-2.0 +%%Creator: dvips(k) 5.95a Copyright 2005 Radical Eye Software +%%Title: ulogd.a4.dvi +%%Pages: 9 +%%PageOrder: Ascend +%%BoundingBox: 0 0 595 842 +%%DocumentFonts: CMSS17 CMR10 CMMI10 CMSS10 CMTT10 CMBX12 CMBX10 CMSY10 +%%+ CMTT9 +%%DocumentPaperSizes: a4 +%%EndComments +%DVIPSWebPage: (www.radicaleye.com) +%DVIPSCommandLine: dvips -t a4 -o ulogd.a4.ps ulogd.a4.dvi +%DVIPSParameters: dpi=600 +%DVIPSSource: TeX output 2006.01.25:1227 +%%BeginProcSet: tex.pro 0 0 +%! +/TeXDict 300 dict def TeXDict begin/N{def}def/B{bind def}N/S{exch}N/X{S +N}B/A{dup}B/TR{translate}N/isls false N/vsize 11 72 mul N/hsize 8.5 72 +mul N/landplus90{false}def/@rigin{isls{[0 landplus90{1 -1}{-1 1}ifelse 0 +0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{ +landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize +mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[ +matrix currentmatrix{A A round sub abs 0.00001 lt{round}if}forall round +exch round exch]setmatrix}N/@landscape{/isls true N}B/@manualfeed{ +statusdict/manualfeed true put}B/@copies{/#copies X}B/FMat[1 0 0 -1 0 0] +N/FBB[0 0 0 0]N/nn 0 N/IEn 0 N/ctr 0 N/df-tail{/nn 8 dict N nn begin +/FontType 3 N/FontMatrix fntrx N/FontBBox FBB N string/base X array +/BitMaps X/BuildChar{CharBuilder}N/Encoding IEn N end A{/foo setfont}2 +array copy cvx N load 0 nn put/ctr 0 N[}B/sf 0 N/df{/sf 1 N/fntrx FMat N +df-tail}B/dfs{div/sf X/fntrx[sf 0 0 sf neg 0 0]N df-tail}B/E{pop nn A +definefont setfont}B/Cw{Cd A length 5 sub get}B/Ch{Cd A length 4 sub get +}B/Cx{128 Cd A length 3 sub get sub}B/Cy{Cd A length 2 sub get 127 sub} +B/Cdx{Cd A length 1 sub get}B/Ci{Cd A type/stringtype ne{ctr get/ctr ctr +1 add N}if}B/CharBuilder{save 3 1 roll S A/base get 2 index get S +/BitMaps get S get/Cd X pop/ctr 0 N Cdx 0 Cx Cy Ch sub Cx Cw add Cy +setcachedevice Cw Ch true[1 0 0 -1 -.1 Cx sub Cy .1 sub]{Ci}imagemask +restore}B/D{/cc X A type/stringtype ne{]}if nn/base get cc ctr put nn +/BitMaps get S ctr S sf 1 ne{A A length 1 sub A 2 index S get sf div put +}if put/ctr ctr 1 add N}B/I{cc 1 add D}B/bop{userdict/bop-hook known{ +bop-hook}if/SI save N @rigin 0 0 moveto/V matrix currentmatrix A 1 get A +mul exch 0 get A mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N/eop{ +SI restore userdict/eop-hook known{eop-hook}if showpage}N/@start{ +userdict/start-hook known{start-hook}if pop/VResolution X/Resolution X +1000 div/DVImag X/IEn 256 array N 2 string 0 1 255{IEn S A 360 add 36 4 +index cvrs cvn put}for pop 65781.76 div/vsize X 65781.76 div/hsize X}N +/p{show}N/RMat[1 0 0 -1 0 0]N/BDot 260 string N/Rx 0 N/Ry 0 N/V{}B/RV/v{ +/Ry X/Rx X V}B statusdict begin/product where{pop false[(Display)(NeXT) +(LaserWriter 16/600)]{A length product length le{A length product exch 0 +exch getinterval eq{pop true exit}if}{pop}ifelse}forall}{false}ifelse +end{{gsave TR -.1 .1 TR 1 1 scale Rx Ry false RMat{BDot}imagemask +grestore}}{{gsave TR -.1 .1 TR Rx Ry scale 1 1 false RMat{BDot} +imagemask grestore}}ifelse B/QV{gsave newpath transform round exch round +exch itransform moveto Rx 0 rlineto 0 Ry neg rlineto Rx neg 0 rlineto +fill grestore}B/a{moveto}B/delta 0 N/tail{A/delta X 0 rmoveto}B/M{S p +delta add tail}B/b{S p tail}B/c{-4 M}B/d{-3 M}B/e{-2 M}B/f{-1 M}B/g{0 M} +B/h{1 M}B/i{2 M}B/j{3 M}B/k{4 M}B/w{0 rmoveto}B/l{p -4 w}B/m{p -3 w}B/n{ +p -2 w}B/o{p -1 w}B/q{p 1 w}B/r{p 2 w}B/s{p 3 w}B/t{p 4 w}B/x{0 S +rmoveto}B/y{3 2 roll p a}B/bos{/SS save N}B/eos{SS restore}B end + +%%EndProcSet +%%BeginProcSet: texps.pro 0 0 +%! +TeXDict begin/rf{findfont dup length 1 add dict begin{1 index/FID ne 2 +index/UniqueID ne and{def}{pop pop}ifelse}forall[1 index 0 6 -1 roll +exec 0 exch 5 -1 roll VResolution Resolution div mul neg 0 0]FontType 0 +ne{/Metrics exch def dict begin Encoding{exch dup type/integertype ne{ +pop pop 1 sub dup 0 le{pop}{[}ifelse}{FontMatrix 0 get div Metrics 0 get +div def}ifelse}forall Metrics/Metrics currentdict end def}{{1 index type +/nametype eq{exit}if exch pop}loop}ifelse[2 index currentdict end +definefont 3 -1 roll makefont/setfont cvx]cvx def}def/ObliqueSlant{dup +sin S cos div neg}B/SlantFont{4 index mul add}def/ExtendFont{3 -1 roll +mul exch}def/ReEncodeFont{CharStrings rcheck{/Encoding false def dup[ +exch{dup CharStrings exch known not{pop/.notdef/Encoding true def}if} +forall Encoding{]exch pop}{cleartomark}ifelse}if/Encoding exch def}def +end + +%%EndProcSet +%%BeginProcSet: special.pro 0 0 +%! +TeXDict begin/SDict 200 dict N SDict begin/@SpecialDefaults{/hs 612 N +/vs 792 N/ho 0 N/vo 0 N/hsc 1 N/vsc 1 N/ang 0 N/CLIP 0 N/rwiSeen false N +/rhiSeen false N/letter{}N/note{}N/a4{}N/legal{}N}B/@scaleunit 100 N +/@hscale{@scaleunit div/hsc X}B/@vscale{@scaleunit div/vsc X}B/@hsize{ +/hs X/CLIP 1 N}B/@vsize{/vs X/CLIP 1 N}B/@clip{/CLIP 2 N}B/@hoffset{/ho +X}B/@voffset{/vo X}B/@angle{/ang X}B/@rwi{10 div/rwi X/rwiSeen true N}B +/@rhi{10 div/rhi X/rhiSeen true N}B/@llx{/llx X}B/@lly{/lly X}B/@urx{ +/urx X}B/@ury{/ury X}B/magscale true def end/@MacSetUp{userdict/md known +{userdict/md get type/dicttype eq{userdict begin md length 10 add md +maxlength ge{/md md dup length 20 add dict copy def}if end md begin +/letter{}N/note{}N/legal{}N/od{txpose 1 0 mtx defaultmatrix dtransform S +atan/pa X newpath clippath mark{transform{itransform moveto}}{transform{ +itransform lineto}}{6 -2 roll transform 6 -2 roll transform 6 -2 roll +transform{itransform 6 2 roll itransform 6 2 roll itransform 6 2 roll +curveto}}{{closepath}}pathforall newpath counttomark array astore/gc xdf +pop ct 39 0 put 10 fz 0 fs 2 F/|______Courier fnt invertflag{PaintBlack} +if}N/txpose{pxs pys scale ppr aload pop por{noflips{pop S neg S TR pop 1 +-1 scale}if xflip yflip and{pop S neg S TR 180 rotate 1 -1 scale ppr 3 +get ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg TR}if xflip +yflip not and{pop S neg S TR pop 180 rotate ppr 3 get ppr 1 get neg sub +neg 0 TR}if yflip xflip not and{ppr 1 get neg ppr 0 get neg TR}if}{ +noflips{TR pop pop 270 rotate 1 -1 scale}if xflip yflip and{TR pop pop +90 rotate 1 -1 scale ppr 3 get ppr 1 get neg sub neg ppr 2 get ppr 0 get +neg sub neg TR}if xflip yflip not and{TR pop pop 90 rotate ppr 3 get ppr +1 get neg sub neg 0 TR}if yflip xflip not and{TR pop pop 270 rotate ppr +2 get ppr 0 get neg sub neg 0 S TR}if}ifelse scaleby96{ppr aload pop 4 +-1 roll add 2 div 3 1 roll add 2 div 2 copy TR .96 dup scale neg S neg S +TR}if}N/cp{pop pop showpage pm restore}N end}if}if}N/normalscale{ +Resolution 72 div VResolution 72 div neg scale magscale{DVImag dup scale +}if 0 setgray}N/psfts{S 65781.76 div N}N/startTexFig{/psf$SavedState +save N userdict maxlength dict begin/magscale true def normalscale +currentpoint TR/psf$ury psfts/psf$urx psfts/psf$lly psfts/psf$llx psfts +/psf$y psfts/psf$x psfts currentpoint/psf$cy X/psf$cx X/psf$sx psf$x +psf$urx psf$llx sub div N/psf$sy psf$y psf$ury psf$lly sub div N psf$sx +psf$sy scale psf$cx psf$sx div psf$llx sub psf$cy psf$sy div psf$ury sub +TR/showpage{}N/erasepage{}N/setpagedevice{pop}N/copypage{}N/p 3 def +@MacSetUp}N/doclip{psf$llx psf$lly psf$urx psf$ury currentpoint 6 2 roll +newpath 4 copy 4 2 roll moveto 6 -1 roll S lineto S lineto S lineto +closepath clip newpath moveto}N/endTexFig{end psf$SavedState restore}N +/@beginspecial{SDict begin/SpecialSave save N gsave normalscale +currentpoint TR @SpecialDefaults count/ocount X/dcount countdictstack N} +N/@setspecial{CLIP 1 eq{newpath 0 0 moveto hs 0 rlineto 0 vs rlineto hs +neg 0 rlineto closepath clip}if ho vo TR hsc vsc scale ang rotate +rwiSeen{rwi urx llx sub div rhiSeen{rhi ury lly sub div}{dup}ifelse +scale llx neg lly neg TR}{rhiSeen{rhi ury lly sub div dup scale llx neg +lly neg TR}if}ifelse CLIP 2 eq{newpath llx lly moveto urx lly lineto urx +ury lineto llx ury lineto closepath clip}if/showpage{}N/erasepage{}N +/setpagedevice{pop}N/copypage{}N newpath}N/@endspecial{count ocount sub{ +pop}repeat countdictstack dcount sub{end}repeat grestore SpecialSave +restore end}N/@defspecial{SDict begin}N/@fedspecial{end}B/li{lineto}B +/rl{rlineto}B/rc{rcurveto}B/np{/SaveX currentpoint/SaveY X N 1 +setlinecap newpath}N/st{stroke SaveX SaveY moveto}N/fil{fill SaveX SaveY +moveto}N/ellipse{/endangle X/startangle X/yrad X/xrad X/savematrix +matrix currentmatrix N TR xrad yrad scale 0 0 1 startangle endangle arc +savematrix setmatrix}N end + +%%EndProcSet +%%BeginProcSet: color.pro 0 0 +%! +TeXDict begin/setcmykcolor where{pop}{/setcmykcolor{dup 10 eq{pop +setrgbcolor}{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll +}repeat setrgbcolor pop}ifelse}B}ifelse/TeXcolorcmyk{setcmykcolor}def +/TeXcolorrgb{setrgbcolor}def/TeXcolorgrey{setgray}def/TeXcolorgray{ +setgray}def/TeXcolorhsb{sethsbcolor}def/currentcmykcolor where{pop}{ +/currentcmykcolor{currentrgbcolor 10}B}ifelse/DC{exch dup userdict exch +known{pop pop}{X}ifelse}B/GreenYellow{0.15 0 0.69 0 setcmykcolor}DC +/Yellow{0 0 1 0 setcmykcolor}DC/Goldenrod{0 0.10 0.84 0 setcmykcolor}DC +/Dandelion{0 0.29 0.84 0 setcmykcolor}DC/Apricot{0 0.32 0.52 0 +setcmykcolor}DC/Peach{0 0.50 0.70 0 setcmykcolor}DC/Melon{0 0.46 0.50 0 +setcmykcolor}DC/YellowOrange{0 0.42 1 0 setcmykcolor}DC/Orange{0 0.61 +0.87 0 setcmykcolor}DC/BurntOrange{0 0.51 1 0 setcmykcolor}DC +/Bittersweet{0 0.75 1 0.24 setcmykcolor}DC/RedOrange{0 0.77 0.87 0 +setcmykcolor}DC/Mahogany{0 0.85 0.87 0.35 setcmykcolor}DC/Maroon{0 0.87 +0.68 0.32 setcmykcolor}DC/BrickRed{0 0.89 0.94 0.28 setcmykcolor}DC/Red{ +0 1 1 0 setcmykcolor}DC/OrangeRed{0 1 0.50 0 setcmykcolor}DC/RubineRed{ +0 1 0.13 0 setcmykcolor}DC/WildStrawberry{0 0.96 0.39 0 setcmykcolor}DC +/Salmon{0 0.53 0.38 0 setcmykcolor}DC/CarnationPink{0 0.63 0 0 +setcmykcolor}DC/Magenta{0 1 0 0 setcmykcolor}DC/VioletRed{0 0.81 0 0 +setcmykcolor}DC/Rhodamine{0 0.82 0 0 setcmykcolor}DC/Mulberry{0.34 0.90 +0 0.02 setcmykcolor}DC/RedViolet{0.07 0.90 0 0.34 setcmykcolor}DC +/Fuchsia{0.47 0.91 0 0.08 setcmykcolor}DC/Lavender{0 0.48 0 0 +setcmykcolor}DC/Thistle{0.12 0.59 0 0 setcmykcolor}DC/Orchid{0.32 0.64 0 +0 setcmykcolor}DC/DarkOrchid{0.40 0.80 0.20 0 setcmykcolor}DC/Purple{ +0.45 0.86 0 0 setcmykcolor}DC/Plum{0.50 1 0 0 setcmykcolor}DC/Violet{ +0.79 0.88 0 0 setcmykcolor}DC/RoyalPurple{0.75 0.90 0 0 setcmykcolor}DC +/BlueViolet{0.86 0.91 0 0.04 setcmykcolor}DC/Periwinkle{0.57 0.55 0 0 +setcmykcolor}DC/CadetBlue{0.62 0.57 0.23 0 setcmykcolor}DC +/CornflowerBlue{0.65 0.13 0 0 setcmykcolor}DC/MidnightBlue{0.98 0.13 0 +0.43 setcmykcolor}DC/NavyBlue{0.94 0.54 0 0 setcmykcolor}DC/RoyalBlue{1 +0.50 0 0 setcmykcolor}DC/Blue{1 1 0 0 setcmykcolor}DC/Cerulean{0.94 0.11 +0 0 setcmykcolor}DC/Cyan{1 0 0 0 setcmykcolor}DC/ProcessBlue{0.96 0 0 0 +setcmykcolor}DC/SkyBlue{0.62 0 0.12 0 setcmykcolor}DC/Turquoise{0.85 0 +0.20 0 setcmykcolor}DC/TealBlue{0.86 0 0.34 0.02 setcmykcolor}DC +/Aquamarine{0.82 0 0.30 0 setcmykcolor}DC/BlueGreen{0.85 0 0.33 0 +setcmykcolor}DC/Emerald{1 0 0.50 0 setcmykcolor}DC/JungleGreen{0.99 0 +0.52 0 setcmykcolor}DC/SeaGreen{0.69 0 0.50 0 setcmykcolor}DC/Green{1 0 +1 0 setcmykcolor}DC/ForestGreen{0.91 0 0.88 0.12 setcmykcolor}DC +/PineGreen{0.92 0 0.59 0.25 setcmykcolor}DC/LimeGreen{0.50 0 1 0 +setcmykcolor}DC/YellowGreen{0.44 0 0.74 0 setcmykcolor}DC/SpringGreen{ +0.26 0 0.76 0 setcmykcolor}DC/OliveGreen{0.64 0 0.95 0.40 setcmykcolor} +DC/RawSienna{0 0.72 1 0.45 setcmykcolor}DC/Sepia{0 0.83 1 0.70 +setcmykcolor}DC/Brown{0 0.81 1 0.60 setcmykcolor}DC/Tan{0.14 0.42 0.56 0 +setcmykcolor}DC/Gray{0 0 0 0.50 setcmykcolor}DC/Black{0 0 0 1 +setcmykcolor}DC/White{0 0 0 0 setcmykcolor}DC end + +%%EndProcSet +TeXDict begin @defspecial + + /DvipsToPDF { 72.27 mul Resolution div } def /PDFToDvips { 72.27 div +Resolution mul } def /HyperBorder { 1 PDFToDvips } def /H.V {pdf@hoff +pdf@voff null} def /H.B {/Rect[pdf@llx pdf@lly pdf@urx pdf@ury]} def +/H.S { currentpoint HyperBorder add /pdf@lly exch def dup DvipsToPDF +/pdf@hoff exch def HyperBorder sub /pdf@llx exch def } def /H.L { 2 +sub dup /HyperBasePt exch def PDFToDvips /HyperBaseDvips exch def currentpoint +HyperBaseDvips sub /pdf@ury exch def /pdf@urx exch def } def /H.A { +H.L currentpoint exch pop vsize 72 sub exch DvipsToPDF HyperBasePt +sub sub /pdf@voff exch def } def /H.R { currentpoint HyperBorder sub +/pdf@ury exch def HyperBorder add /pdf@urx exch def currentpoint exch +pop vsize 72 sub exch DvipsToPDF sub /pdf@voff exch def } def systemdict +/pdfmark known not {userdict /pdfmark systemdict /cleartomark get put} +if + +@fedspecial end +%%BeginFont: CMTT9 +%!PS-AdobeFont-1.1: CMTT9 1.0 +%%CreationDate: 1991 Aug 20 16:46:24 +% Copyright (C) 1997 American Mathematical Society. All Rights Reserved. +11 dict begin +/FontInfo 7 dict dup begin +/version (1.0) readonly def +/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def +/FullName (CMTT9) readonly def +/FamilyName (Computer Modern) readonly def +/Weight (Medium) readonly def +/ItalicAngle 0 def +/isFixedPitch true def +end readonly def +/FontName /CMTT9 def +/PaintType 0 def +/FontType 1 def +/FontMatrix [0.001 0 0 0.001 0 0] readonly def +/Encoding 256 array +0 1 255 {1 index exch /.notdef put} for +dup 45 /hyphen put +dup 46 /period put +dup 48 /zero put +dup 49 /one put +dup 50 /two put +dup 51 /three put +dup 53 /five put +dup 54 /six put +dup 61 /equal put +dup 62 /greater put +dup 65 /A put +dup 66 /B put +dup 67 /C put +dup 68 /D put +dup 69 /E put +dup 70 /F put +dup 71 /G put +dup 75 /K put +dup 76 /L put +dup 78 /N put +dup 79 /O put +dup 80 /P put +dup 82 /R put +dup 84 /T put +dup 85 /U put +dup 87 /W put +dup 89 /Y put +dup 95 /underscore put +dup 97 /a put +dup 98 /b put +dup 99 /c put +dup 100 /d put +dup 101 /e put +dup 102 /f put +dup 103 /g put +dup 104 /h put +dup 105 /i put +dup 106 /j put +dup 107 /k put +dup 108 /l put +dup 109 /m put +dup 110 /n put +dup 111 /o put +dup 112 /p put +dup 113 /q put +dup 114 /r put +dup 115 /s put +dup 116 /t put +dup 117 /u put +dup 118 /v put +dup 120 /x put +dup 121 /y put +dup 122 /z put +readonly def +/FontBBox{-6 -233 542 698}readonly def +currentdict end +currentfile eexec +D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891 +016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171 +9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F +D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758 +469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8 +2BDBF16FBC7512FAA308A093FE5F00F963068B8232429ED8B7CF6A3D879A2D1E +2931CE5F5D18C658602059F07BE66E6EFC9239D7AB2FB8A4CBD41675B8ECF279 +650C29E53B14AC0E392A664848C1844B1CECBB2D5CFB72D0916B675C9A9A1E35 +F12696A6F628473C604A95376468E06E295AD6F76CEB939D94113532050B9D5A +D2F41A9EFB9424D986612313B89EFE9C8A71313340B248F6853B1EDBF02B7F9E +F447220FE131D7D54CFB8AA1281DBAEA73E665BACB1F164552CC0CEDB63BD4B1 +4A9AE8AC6FA02242DBE8DA46B64B6BFC11762F0784F216FC8B9120D688D1705A +438B14F5E5DEAF2A98408B3B64620DE3732A4DAE6D08D5D97E34C75DAE19EABD +BA0796165C1151BCBFB1DF8D29A63A8300DBDB9E3323CB82D0337598B83F4F2B +A97CF5196D4D1CEC1EDB8966E548C0D9C194C932319610FB43EA1B86322FE641 +AB48770FF13BD475A7267E142388563D1A400419C585B22A9886074687BEDF74 +D905BE8EE440BA2ABF28EAB673399B7F129B9729DD5564C681954621903B84BB +CAF89AC5ADB2932472DF29ADA2BDBDB4D05F65F28F5F4C529613D61858E0074A +082A852710A62A147C966F2B85B51B0BE85F11D2057C66FDD61F6C5755367980 +9F4DE680601D4DA41B46F8D2148450000413C27AA39B586B74B977B25F0FD3C0 +4BA1EBFAFDBEC531EA1210365091671CE3C86A6D4BC591C37DCC02570042575A +9D24252D6E01A8603753934D7EA5CAC1BE4E5AD2BA047DE8F3983B23A8A1511F +B08D373B69E5076CE4300137B8805EBCC0AAB89BBB312A77835795E3C069322D +42C893A30AD739E2BDD299679B158F7493764F2321E3965141B5ED1C6F4765ED +F46D391A646B30C90002B1C461AEE79E5F094CACCA656CEA3DB921CC5205F328 +A2C69F817061D6C60B121EEE844CA5008F23DF0ABE08642EF69D6C681B6BDCBC +5586F5DD6A165551B7A36F3C57033B4779DB294EC54D9D576D9125C431AC5BE5 +5241C4FF4A5ACF8CC1B87C9E1E9B12865B035E5541621E77E7C007EA1C2434FA +E4910F204C63FA83B3602F3EF982C37D976012F429230585764307E71EF4FDE7 +851CA12A82F347D852E9726A4F91F53A1B3B77F299272740CAE1A06604B087A9 +2FAB73E54F41AF6CCF640E6066CE5977A198AD0003D9AA6CF03D5309BC7FF8F1 +85D5B18AA07052830E10B2326CECC0878C49F1EF71A0EA49CABB79DC83931543 +F595CE0500E5B5AF4136F94C73A83617290AB0E8A4D194D1E72A6CF3F1C4BE77 +B6C878A6EBAB28E56F5BA4136A4B858CC44106D4F736AEE17979183A3056E5CE +D416A9CB326AA0941344BBF74001A09F4E629F9EDFF79A5E23E1D0256FBB34EC +FACE9C363A7FB43F841E739E325478E0C70E2978EE6458073B567501AD541C25 +F661D0D9783765CBCC8998E6F724195B5A588FA7C8CDC21008CC0AB135EEDB3C +4829F4DB76CBCC1F750B87D2DB4C07EC182EB120A98B65FE6E1E89A2AD7D1840 +ACF467195CCACA9ABE5316E15D013251472586D623B7702D0799C2D710E84C0F +501C7BD4AC34217EECB1D55826A3E6D7D6B86E4FC8C52693A9E05F148F51992C +876E50903DC18D25A3B2BE7BBA526A27C4FCB22C57FCAB479FB50E49DA0D83E2 +DB64B6879F49BB4D76081EF7148DE4733FC6637F9197441CEB6EAD9EF97887B4 +31F32DEF46540CD7DBE4642BBFC4D8307B3483F6ECF42ADC172BA093A73F3C4F +41FE73348F57F36458A477A65F8FCAECC197BC4D11AE293BD48FF249F01F7029 +E947CB00CFF75C1360B066DC5BBE7215FDF7760B8635C02E14399570651D7B38 +52880EC73CBF9DAC213B60AEC3F5AC678090A581D27E1D3FB63B42DB8963A37F +74979320B26DC3770BDE0A56F1BE4E30785297B4736DF2BE27C1A76AFE09C793 +19D83DDCD82D388D6189F7EB025024CE405BFE9FD9F741D60CB4A2020D5F6D0D +C73E0F59A3DF7CB710DBA902B944E1B918AB2B90010143AE5D5985C35F0394AA +C0DF49D05043C662832240D3F09CC4C23D532A53AA556FB052789826B071737A +F9CCF8B6629DD542E891C48AA86A8597A021C0D2D71B5D79347798BFAF91FF44 +BD1064D8D2D756D1BFF2DAA634CC50D20AC158200D04D254ED553CD12C5F8CA0 +E76C1557CBA9374A7E6D2095B104A04D45AA349C96B9F6268847EB420D71FF02 +76EC8E7974EF4B66D97A0236A0748B07E2609CE8FEBDB6DDDA05D2E79A74259D +C6B5E566746CE0342AEF5477A80010CB482E52440841F61841FDC3250BABC727 +7FE534536815E3435F7F9C31B808779466AABBA346F7A4CDF0A3FCD5B39B7E11 +5439FD28E9B1A01B82C2BE0A3AA02809A23C41130409121EAD67C90A5D91609D +9119077F0820286149C85D15826D67A1E60AABBF1FD3A4716D401E294013F40C +7E0295BA7F575717A2330063FF876ED6F30D428F59B23C557DDBC24D04A32CA4 +DA8370668988E4D2407CB97BA3220DE8C71C1B65D6F6609728E137B8355ABE27 +F8D64568A56EE7CEB5314501D523F79ACBD9026A6A0C616AF611C0A49DDFD555 +315B47853AE1318257634F2F55356C234755B72984901E719476BED83B9711A6 +0511614667FC90C9DD255F9ED60828F298DE410E97A1AD69D9665EDEF4B788F7 +2F812835E25EB4C0E11D704D5D0E67F286F50566467EA97005FBFB7CB42AA873 +C9970136FCB329955BE4261D33E44E0A55A411658EB05118F7F6D56D1B404F67 +4CFDAE496F361A47FD32C23DF17C4A254B0FEC9548DE220D914F55931298B75B +D3BAD307ED14E3CF287BE6E7BD6522FD2A162BB09C7AC93906A9312CF197DE81 +A5F097F6BCFC89E3F46401C960C0D985C6BA4281D783853DA65CB86CA24287C3 +6BECCC7AD90ACE2877CF6E20D6CB5E8774AECD16F4CF5E6AD4387C63CB4B2988 +732802AC9FA0E6E81E16EE0A133E1ED5AB5B6AF8DE17AD45EEC347FE1395E383 +E59EDD32B9484701913E9B998BF2AA10D404DB538B8D6B65C2291381F35FB794 +1F2AFC236FFFEE0C6F1032FE0919E55E8804BBA5DD683FA0C7729C1A7625EC9F +33C8F0A537C425AA270E47ACBF35E5DE9D5B666BE8F775AD1A9255E9CC61321C +7FA5ECB949FC1C99A3BA97F499FA98E99067AF06ED297DBCCFE264A35CA1E812 +1362F85D6F7BC124A056D5E2B81110688BBD8C28E6FEE3C2870BE852840F94E6 +B020F9B90AB09EAF34C345B3FA2BD531D79760BF52A2EB366D761F739C8FEC6F +DE1EB216F4AFFEC742C6791903F30DAB4E946051E93D2AA6D57590E62DA1AEEA +04539517096069A8EF7AA1CE23FA6BABC245F814BF8EA8F88D8C7886563D7602 +F71936B5733DF34999C3D565EDD0A7E53763698CD9F33B11DCB41D77991EF2E3 +86A67DAE700FEEBA6EB4BF637D06193BD029ED2D99F365825191F4D49063827D +8F6891BF8AC7D8BC00A637E19AF9805D14D04BA158983EB1A37840B36230EA82 +FDA32C9A2FEF9E986B66DDC9DE172F7E04EEC3D68CF69FB57AB0D3D5DEAF5C2F +54D58266B4EA42F544CE1C30B03BC3BF5C4FB40B9E6CF0EB40B4D5B1E917908A +2B3ECA55B26A68F9DF960795C1934EC50DF29DC169C2CFA9D845FC164FB2BF9A +283C5220D3D4C24C1554896C5FEDBF7F690BC776CDB2505479A552D3FB3F60AF +6D9EA1A86EB148AF06F61F060143226C991511B19EDB4B491AB24BCE9269ACA7 +03D7BCE148B7E2D29711B6278643D73114EA74A7B97EE1D957FF00F09C7724A8 +5C16494D8D5EDF90A154BD75BE2209F941738ABAD2FA4FF50D0C8C7C5F52043B +BCD40F64D211D53F5784BE91573A74E46163796F7A8A7C26C8DF58361BD0B2D4 +69A40495A6BB8D1879B168ED334177F2F3C36D0843A9862CFDA1FE11C07E5D98 +578188A287543A51B732FFCEF7D48D50302A06B1563606AF9404C8233E26F95C +A95CE5BDC103416938307099072B405DE07409AB0BEFFB023FE3735452536CFA +CEF7E6EB829A92ACFF641CFE56A426585D0E8F7D8E5F90F2BE9A0AAF9B9D0880 +D9643C5828BD66DCFCF1B5D1DF461635AB134121F128604CBA0265497BC411E5 +F8E7AB57B195E333CF4C4FA63CAAC974BFEB3A9D157A26F6149E986D83C1E6A2 +FA9E9836066BB0973D5B9E132086B40B1957C4DE6BAD8C06F86A8E806E9E91E9 +83D1F6A4DB3521688E2DFEB42EC80F3EEDE7E0D98DE7B48E126736A3088795BF +AA22AE968ADDB07F13D1A68CB04C69D82A4F4244CB4861C4DCF04D1693F44CEB +3FADC0176D5A5CD21C44F8680297653F7D6307F5C2D3A8BAEE3CDBEF18DD5F02 +FA95FFA9104A2C23303D2E27B69EE41349C2ABBCB7EC9139726BE1E017DDBA98 +B7F42EBF0E9816502D1CFC097E2CEA2B5AC756A5ACDDE218575B65C2EFD85892 +5D975F8F655BF7937B3898E4C3B8FE68B8601666A3F9DE9737823BD96119187C +08A0EE910740ABF6DAE955BC02FDBBEE621804D43DBB83DCDD42D477EC6E895C +C7CB698345129988F6E273AAF4538C94591C5D0479E0986DC8E64CDE1EF71122 +0D13E5C4B8EC783023B54DC4DE6D820D1618D0E9CA945B2C122DA02BAEDC74BE +7E64A00C7132B9623E23CB5C3077462559AD713D35524B60FBB76471840E7B47 +315C10F01047A5E710EDCA3BF680C8E92EB4BE5A6B25D10E2227BB9EA1BD5673 +017F928F9A68A9F9DE20A97E7935DD660A2C965930B6E008077429D0D4967422 +E94C2DEC87DC0ECED0228E9D6DEB7B706526D464F731915E54EB3D4B9BFD2C76 +D1C6EAC4B8336B4507959E689C2DD99BE5A87103E8A4215BE167670EBDB1D819 +D4D671A9616E0F7C00FAF2981A3A56BE5E31584F049F684D30FC8D9C5A50C0A5 +8B66AB11605D38A37D3B801A14505C4C7941A8BF6B2651EDB5DD6DCA4AA1CFEF +E8CAF445D7794FB16E52ACB714922DBC440EA357E55E7367AE02270618E84568 +2D0623BE785C66D6FE8C76969E2D104D7404ED50878D7D111330C922CA7E0683 +06F3E323755400155B959A4DF8BA32F87575630BFA7B4841A8AE978B41AC258E +145931EF5E33AD78D57EB31E6989B4A832B1A3DAC92120B0213A075BB7E1E8A0 +A674ED7184B3353F818974611319A8388BDE2DB96FB4DE74C3901141739469EA +E4B9154219C3089934EE042CA074F5979EC0043BF0FDAFF54568E2E113C8C56F +7ED736D085C2E6664AB5CC15B09F780002B5DE9D488609CEA3540DBAF766E3A9 +C0EA8F59AD3681770A8471EE38D269C1F07CB4D7025CDB7F72530B0521FC9FE8 +43F896160DF271C89FB10C9EB83BC1A1E3818489BA4D86B93D17E8D6C44CFC53 +23067A61057D3408F0D76F2AC18D29E04FBEFCAB87C1A8C2F2DC25DE11A89F10 +1B4EE85384DECF7928F2E6DDA9FFEF52A7B2547672CA87B0D446121932EEF150 +6CE0DC9F752A3F39AD7D0901F242F05DA1457C82E4A809C0654B4770EFB4C202 +EC628C9691F2E503CE9EFC39120034DCFE78307A8E25E190B66E161129EADF6F +F4CAC84B2A696846AF1551BE8538E796377919B1FB5F6BA0CA75D78AD31153A5 +D433642451FB373696DA3CBC16A44226EB65D3C0EBAE1F2DC6BEF9D04783359B +E03B06EA1A222C7BD5F974EB282C901CA14EB5AD616FFA7A135DF96E04EDEEB5 +43BEE44FACE82107D42215F7ADFBA8C588768DE2CCA86CEFAB9F33DCBB974839 +2C8A292B9DDF2F9D92D3310112AD2D866357C23B258AA1CF1ADE47E5C318B269 +F471BEDE8AB088AF9161B88067BC141B32ABD013590E624F006B7875AF019774 +B6C07329D743B5BF4B584F0F58FCE1407895DB429BE1707885E80B632EC2F25A +B94E1F7FA2089EECA10AF87B1CC23E0CDCE779C3B7385A2A40D5059431034F0F +A2200915910947E4D85354DC766E5D745F51105205FD0F4673E57EE47AB916C3 +304370707065AF4FAA8BE751F6FCC8EF7F9F8C6057FB46E852D38EEA3F6947C5 +0448CCB44888463DEFF05540357A682DCC95CC60D9141DFF129073F5C9EE7C63 +1EBD82DF63F7038C7E67E4D721DE19879E8B896D805921E982711690691B930C +50325F67F7BC581797C2BE54FE0CA69C49C233D3F5FD9CBF4E78133CE5D5E125 +6F35B7FA773957D1057656821B6E7F3310E83FFD2383D7E443DD40E517F3A58D +CDED3AF73DAD2B33AB448662A360E3797AD97C62FB3EA5C9B91B3AF6E0A8924D +DA93C3222CCB25EF3980F18ECBB7B232EC2865B95A7C16F5869D4469BEBA2DA8 +7A1794E88BD03584DF300475AF44A662122C9B71FF02287A7A40592EF01E4D87 +CE51B056358638B40EA28E6CC7EB1093A750C568CFFEC56A7ACD172926338FCD +4EB3E5BBAF047F07E78EE101A857E26A19B867613CA8EE1087724D95E14CF1BC +5CE4AD7131B50308A299F9E378EA6F75A1FD31C7C930E956ED81CD68696021A2 +A2B5EADEC2068AB2C6190F1B76E022F1115F4243C8563770C834A6CCD1D2BC77 +379EC261D16D82FB097787B9BC8C621A83BFB5FDABC8348A59384AC06BAACE2D +861D45CBB79EC4A4A5CE9550830372D58ED335770C267227CB2E0D61EAF2D2EE +A753731E5836D50FD703F422D942C16A09648B920199EF91349121AAB2697F53 +BEDFE1BA405D46094901754322730825708E7AF35C29D96E0D7045B1F845CC13 +F48D29F86D4E16B87D1869125E247F9F3590896D98847A547196343E2424A635 +ED134E25FD6DA3B3D7B191FE2183560A45A0BF76498A9D7FA7C0493E9B581618 +6CDD5DA669E02B75BC06E64036E1C0368C6629A3A837BE3F05FE0CA21262E5B4 +B3196B79B6F0567A5C48D5EF4CC58BF0EC765134F5748CD3B41CFD93733EC5B6 +A5EC2F8259C7708464F86CD05BA3365CC3696F4C1C6ECC0B39865970490FD685 +1EA49EFD81AA5CEB3A942018AB864FC3EA60C07584C3B68EB0C0E4BDB204C78F +661C140C809C0370F03347E0BA874B369CCC9854503402508D78E01291AAB2F4 +696AAFF1AA468214261E259698F888EE189739E6F9D4CEDD9916705A683DE7ED +A52E8FD6426C9849AC93E2AE350FC6E90E0D52B72ED1B844A0ED1B9344F4F7D8 +31EBB7CCAAF9B5F1156D63927C92EE390FBEB5B1F9D0B9797FF0B47078305FA0 +FA1EC1A6D0BC47C0C6E87085F43177AD0368B24B33234CDFAD69B5869C3A0229 +21BD410C597812AF5C082A64824589EBF401FB26974EEBF2575BE1F876F94518 +B219251DD0868840B67BDC7DE65AF0D7A16C5CB254F3A306AC48776DEBD0D9FE +F613CE625ED330A0EE04E956B3C6AA7E8C480420F652794C5C1C6A9E01B39D68 +9B6E6E3C1DF8A6E9C9C3808B4E46875053362039282554C66125F9CDDCA26B9C +1DF221AF3D74D5E762CF2CF576C085AB537968BAA6B40DE4876B7233FACF95E6 +8FC5C45CE837ED76C264F19B7D01071646C28FB55D5E2D5C8A577CED79334C5D +4EE36C4FA1916404C42D9274885A479050BE8FF9D3874EA492A187756464FC55 +D2967B4BB0240D582CE337B74EB9989C81A8CCC591A32F5AC9C75A5C37129B81 +03C31E6526914D5AC7E87DC9086E248CEBFC5D2C3A1B94F119B1A5712A497754 +04FDA20257D37CB8B1DA8A89C717AD475486B7135065F332D48DCE841561E1B1 +4CE5B2FF8034955FD7966C070A334838EA7499C6ACC1639798DA693964E204EF +E724DB3F02F746FD716DDD28ECF5607936CFC09FFB7A090C1E9FA14973670830 +5F809EF7C0B518344DE5ED5BFAF23FD1229B25F564ADF44177467D42F8BE61D5 +28FEB0D13B36D0CED5340D34E9C49AA4F64AE1CE533F2895E889957939070052 +1DEA3D7E287FD49EB0193C9324A169530EDB7DBC48A9A5B392023A72BEDF0463 +D87C249B9A68D42AEC778F9413D78FFB590C3BF07564F1B1316622815EB57397 +D9EFE5EA1FA8214B3BE1B53152F200F281DD79710FA38A7DDA38E54FFFD46F08 +9E8E1B8A5DE1F63937D242304B11765E3E40F47C1626D6E95C7E7DE55EF38AB5 +205E190C359CF8B87B4FA7B8DAE5012A0907E169B052545ECA9F74755F7EF618 +1DE32385DFE726D6A22B58C4D30C1FA8CFBC85AEFE32E88209DC8643B67E1AC2 +67805E0A486041ED2A8CCF37A7031246415D30BBB7B50E807FE81DEE1512CF2A +F3A83F5C516AAE0BD194859EFE1E47CB96863F993452683E9650A70EE4AF1268 +E0CEC0242B146EDE3E35581B6CDC4F834983619DA75D1EC2758B4C96A9BA1311 +20482940818B0D397096914936737AFE3503D0C829E58501E963C36F9250A8F6 +9D6A07C8BFD116D610ABEAF9DB1E7CBE4B456B9D4D77480CFA94618B7CBCC2B4 +490D492D6121112EEED3ED9A7B23CF1B3C9323BB4C301F5CC2EF52D3E8CDEE14 +47891C633E6D4A280FABA68259C0097AEF40779D73960D17A7544ABA1FCB7770 +182671227803551668526B32FD1CCF9B3091D23EEFDD2D904F00F634999DAAD1 +B8FF8C24D40E93E315D4AEDE671A0F64F668CBD5C441C1C9EFDB4A6B7049BA40 +40C40C1F84F08DDC350C1E8202B85A2EDE66A187E4B3773C84A1BAF071353D41 +34C9CA5042674F87BE37F0E325A4D710D342B8DDF1DC13F8C857CC6EEFE6F446 +B46C8B9F100AB40C98AD5BD5B7D0335CD83EAC679E63AA5D4B480C362F11FEF9 +68092E92C987D4268524947A4F889D6C84EB73C66AD0CA74837CF9239FBA7365 +5AD74990C2767CE8B70216B5D7AC59ECFA9C78807FBD38821516F1B55AD128DA +1B0425B8FC8ABA7E6E79FB3BFFC73182F0C86241CA63F547AE17F41DCF6C72CE +0B5FE6C939AD52C54BDEB5DDE25A4D480CB2E33A6BC7868977F28123A5157CE0 +F8B07D333CD1E50E0778E5E6525FDEC736A7F0D5B491A014711A75A41F26EF6D +93FE711727782735C903732BE6E2904FC0848E5322B3E9599A964853D0BC6F55 +B7EFD19014A30005C379AB3B12461F3D3784988AEBC097481C62939402DFFFFD +53844B1709E05BBBB66F818B340DE459D722B4D64D9B68F989AB52A0859D1CF1 +E40FDAC60872408BB85EF20E060B18F92C2FE44E48EB5856DD8BB90B80B8CBC8 +BFC8D20058EA793D456B133E2033B19EB5A416E1AFD68656CA16CBEBF4A53096 +38EAE65C78D82700DB5EEB0EA015F0057697E55D11463A401397C191FF3A6DA9 +07C1ABB91133CCD457F7C7DA6DFF807A338BCC157DE074AAA49CE0BFE1B802D9 +EE2DAA8954D1500E592684FF70C72AE469EF3E5B4E291B537D8A2C4BF3670CE0 +BCA853EDC8FEA15B8ED9E618EE2EF1BC9465D49E0D9D087D4D9C1FED5481A7E5 +A3B73EB53C63B072B2A62D0C5A8B21C7AFF5CBC1706BE9062C091E31061DBCAE +176B9E25F82517E5B55FD224CF76AC5D491F7A703A92A9C1C274EF00561505B5 +C3D6634E0FD3C563CF209F9513F2CD7816420185896ED816FA428A10EB1489E5 +1C16C6DD84C17083817201B88ED34C8F20DE311439430D049C4846269EABF339 +EC446E0CC2395D63B59CE2A6A671A536A3D366920081D55200A2B3E03967F5E0 +F4DC15D0868E5B62BB445BFBA8FE30DF922DB455ECBFC3DE9FF83086173FA2A5 +F97E09A5E04A8DE069978D07DF970DA263C82429343DB5B4DCE60CB9C638ECA3 +596D9F51CB37EA1715DB55F38A05185758B9502F36795DC9C061C19F055BC01A +1339C8870998C98E4177431B67C74407044C4E041C706E0277B836809363B455 +5640A95A165B9FCEE97FE0834FA0229C26FB4B0FD6C903C23404D0EFBF3FB9EC +8F92DC97ECC69B7DCCE85D5C6D24A580463BCC5497D30B76E544517DF84E28B6 +024DE6601977B81C88B764AF11AB9829C5CFF3D272B1EDFDB589EA14CECBFDE8 +C5CE0C01F61135B7332A010AFDA18EB5894CFBDC1BD88F33B253D540F02B2C16 +89168DB0FD591E0B2F9308DC21237901B2047EA8ED57B65785EBB51C118C1394 +79883A9ACD6E1EF322638D0427F93C8330D919F736979A67B3C30CFE7A2187D8 +7A9704E327B1FDAEE6E67014D68DC312E02F9B9CD6020E991A5CC5CF631DA1E9 +3884D75C5A7269D4269B75B57F8C6119F6686A5C91D94D71AA08B1B4E5DD9471 +8EC0F35F8865704656431AD79FAE61DF5A2A8E4D343E13338860F3D7616B7B60 +50BBCAEBCFEEA7ED234DEF8EA7CE794093FEF3E38E152CFAE7339E32BB1957A1 +D4F3FA6F8C586F2F0C1F87B790F40E0DD518CDFAAC1164E3FCB2A495E6E7F955 +89ABC6AF4A46D99BFB5BF646420B0DE04A3B46CA9C37F6328CD259A2FF3CB3B4 +8684077ABFBE04C126E1191298FE364FD2D13A6CA1A9A5D438E4F533D847FAAB +08AA2CC74E023781654357CFA35DE9FB1A9D997439C8CD63704A04103E8500FF +AABD9ECF4B6423B61FAB2C0D1844C5CE958546811D2D179B8AF68AE28FACCE36 +BB334B5F88A545E26BD84AFD889D21755091C250388B35446849BFCC89070D46 +D6421A2E4105945943548DC9F1BB99C615BA21531AFC874EECFBA16E19ABFCB0 +F430B63F190A63B584553D6A45ADD9DB7D6368BF4B137761C93ED1465200C89D +4B93B4EF21E1727EA12107355C23302632BCE8309A8D22BB6C0049B234450AE3 +EEF3818002958980452BD3EDE3BEB1EF03A6B9AE5756B08B3CFC377370BADF78 +8582A5652D79270050828603E1B49968C6B81B62B32524CF542EE045F18D63B4 +0FD2580CF1678A5412548F5FEFA29FC896EDB2E51B6D2FB18E6C585E5E884D53 +4D2DCBC05C9B1125999B16D5D46181410FA8C82465E0573331196020C65D6758 +335DA5EF092E55C1AB65DFFEA1FFE8EEE916F2B68BA99594E1E38A7FDB1B6EA2 +DC8C8AB55AF8CDC5AF93D6940C57AFB1FBCE15EB5C5DB76F8A151986B866D616 +A5CB0223521D909B24DCA91A7AFC341082420E13808153D3965A7AE23EF998F7 +2C9A9B2E204E6C0BE8B00338504F56727DCF39AC4DF3CFF73C9D709C9D19726D +033C3D10374D0C7C3CC783F63A56D6E4EB10FEFE62A996D515EC9041D02123EB +3B977486CFA2CC086F7945609028C12D52C30A2ECA97D94D91AA31F0AB799ED6 +BA08675206E108AF1C166ED31524D77337FA50EAC805AC2D99CE4438E6657A21 +DB7C5AB9EB4901D99127BE024ABB20C5220EAE09B26467E2D5ECFD8BB1301F03 +9903D0BEF297F12A23F645A5FF3CDF5EF246C7546100B31002953CC15DA2B6C9 +076DF8A38D9645D3975C34D12903249E5156F0E000B8C4EA9598D5CE0FC06AC0 +53347651F29006038821194D1EF37AA669339AD0E592DDCF8D9F63CDCA592C81 +883F9841F4EF63A968F7759742579A36564834A4E7DD058A4FC06225B840DDED +13E60DA09D38CAAF7094E5E332C49FD9E666F6158AD665F0E1D4367DEFA87BE9 +43A668F2F4582A67E732B4CE06979D3F53E15145F6C7B631E63D9350F1E5674A +F39EA96612AF34AAC5D099D4B6556B50ADB545CCE4354CA5BE2A297EC1E34F56 +EE69B3784B43F131E4041C9F2AB00303C3FCD5F0F8F4E2EE9CD9DC086200F4F8 +8A87186DD3B79BF777286C276641D7FF9009A2142FF755B192BF9C4FEBACE5EA +4A27BAB8094774C400FD33AC0A92EC3A711A116CA122F13DCA28F9F6CA401DEA +37716E92DA444D40B0FBE41128040F5D9C99CA258AFC1D10441F46A503DE815B +BB2A597CA52AD24190BD598DEDBF607F9B86515697B10F75157EC62741C31665 +E3FFBF40940CC333659F22D7D3A80621FEEB0DCD339B1FB9F4C0999590A41AD7 +518101D804207E7A07DC4E2F8AC5ED2FDA01637CE11F60E2CC22014B6E64F099 +74ED6BE1DDF33428FC5977A50F192AF5F2999B921E20501607EBB365753548B1 +4CF115E2E7F9086E47B56F34A51F53F1ED +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark +%%EndFont +%%BeginFont: CMSY10 +%!PS-AdobeFont-1.1: CMSY10 1.0 +%%CreationDate: 1991 Aug 15 07:20:57 +% Copyright (C) 1997 American Mathematical Society. All Rights Reserved. +11 dict begin +/FontInfo 7 dict dup begin +/version (1.0) readonly def +/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def +/FullName (CMSY10) readonly def +/FamilyName (Computer Modern) readonly def +/Weight (Medium) readonly def +/ItalicAngle -14.035 def +/isFixedPitch false def +end readonly def +/FontName /CMSY10 def +/PaintType 0 def +/FontType 1 def +/FontMatrix [0.001 0 0 0.001 0 0] readonly def +/Encoding 256 array +0 1 255 {1 index exch /.notdef put} for +dup 15 /bullet put +readonly def +/FontBBox{-29 -960 1116 775}readonly def +currentdict end +currentfile eexec +D9D66F633B846A97B686A97E45A3D0AA052F09F9C8ADE9D907C058B87E9B6964 +7D53359E51216774A4EAA1E2B58EC3176BD1184A633B951372B4198D4E8C5EF4 +A213ACB58AA0A658908035BF2ED8531779838A960DFE2B27EA49C37156989C85 +E21B3ABF72E39A89232CD9F4237FC80C9E64E8425AA3BEF7DED60B122A52922A +221A37D9A807DD01161779DDE7D31FF2B87F97C73D63EECDDA4C49501773468A +27D1663E0B62F461F6E40A5D6676D1D12B51E641C1D4E8E2771864FC104F8CBF +5B78EC1D88228725F1C453A678F58A7E1B7BD7CA700717D288EB8DA1F57C4F09 +0ABF1D42C5DDD0C384C7E22F8F8047BE1D4C1CC8E33368FB1AC82B4E96146730 +DE3302B2E6B819CB6AE455B1AF3187FFE8071AA57EF8A6616B9CB7941D44EC7A +71A7BB3DF755178D7D2E4BB69859EFA4BBC30BD6BB1531133FD4D9438FF99F09 +4ECC068A324D75B5F696B8688EEB2F17E5ED34CCD6D047A4E3806D000C199D7C +515DB70A8D4F6146FE068DC1E5DE8BC5703711DA090312BA3FC00A08C453C609 +C627A8BECD6E1FA14A3B02476E90AAD8B4700C400380BC9AFFBF7847EB28661B +9DC3AA0F44C533F2E07DCC4DE19D367BF223E33DC321D0247A0E6EF6ABC8FA52 +15AE044094EF678A8726CD7C011F02BFF8AB6EAEEE391AD837120823BED0B5D8 +F8B15245377871A64F78378BB4330149D6941F7A86FBFFC49B93C94155F5FA7D +F22E7214511C0A92693F4CDBF38411651540572F2DD70D924AE0F18E1CD581F3 +C871399127FF5D07A868885B5FF7CDEB50B8323B2533DEF8DC973B1AE84FA0A2 + +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark +%%EndFont +%%BeginFont: CMBX12 +%!PS-AdobeFont-1.1: CMBX12 1.0 +%%CreationDate: 1991 Aug 20 16:34:54 +% Copyright (C) 1997 American Mathematical Society. All Rights Reserved. +11 dict begin +/FontInfo 7 dict dup begin +/version (1.0) readonly def +/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def +/FullName (CMBX12) readonly def +/FamilyName (Computer Modern) readonly def +/Weight (Bold) readonly def +/ItalicAngle 0 def +/isFixedPitch false def +end readonly def +/FontName /CMBX12 def +/PaintType 0 def +/FontType 1 def +/FontMatrix [0.001 0 0 0.001 0 0] readonly def +/Encoding 256 array +0 1 255 {1 index exch /.notdef put} for +dup 12 /fi put +dup 45 /hyphen put +dup 46 /period put +dup 47 /slash put +dup 49 /one put +dup 50 /two put +dup 51 /three put +dup 52 /four put +dup 53 /five put +dup 65 /A put +dup 67 /C put +dup 68 /D put +dup 69 /E put +dup 71 /G put +dup 73 /I put +dup 76 /L put +dup 77 /M put +dup 78 /N put +dup 79 /O put +dup 80 /P put +dup 81 /Q put +dup 83 /S put +dup 84 /T put +dup 85 /U put +dup 97 /a put +dup 98 /b put +dup 99 /c put +dup 100 /d put +dup 101 /e put +dup 102 /f put +dup 103 /g put +dup 104 /h put +dup 105 /i put +dup 107 /k put +dup 108 /l put +dup 109 /m put +dup 110 /n put +dup 111 /o put +dup 112 /p put +dup 114 /r put +dup 115 /s put +dup 116 /t put +dup 117 /u put +dup 118 /v put +dup 120 /x put +readonly def +/FontBBox{-53 -251 1139 750}readonly def +currentdict end +currentfile eexec +D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891 +016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171 +9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F +D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758 +469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8 +2BDBF16FBC7512FAA308A093FE5F0364CD5660F74BEE96790DE35AFA90CCF712 +B1805DA88AE375A04D99598EADFC625BDC1F9C315B6CF28C9BD427F32C745C99 +AEBE70DAAED49EA45AF94F081934AA47894A370D698ABABDA4215500B190AF26 +7FCFB7DDA2BC68605A4EF61ECCA3D61C684B47FFB5887A3BEDE0B4D30E8EBABF +20980C23312618EB0EAF289B2924FF4A334B85D98FD68545FDADB47F991E7390 +B10EE86A46A5AF8866C010225024D5E5862D49DEB5D8ECCB95D94283C50A363D +68A49071445610F03CE3600945118A6BC0B3AA4593104E727261C68C4A47F809 +D77E4CF27B3681F6B6F3AC498E45361BF9E01FAF5527F5E3CC790D3084674B3E +26296F3E03321B5C555D2458578A89E72D3166A3C5D740B3ABB127CF420C316D +F957873DA04CF0DB25A73574A4DE2E4F2D5D4E8E0B430654CF7F341A1BDB3E26 +77C194764EAD58C585F49EF10843FE020F9FDFD9008D660DE50B9BD7A2A87299 +BC319E66D781101BB956E30643A19B93C8967E1AE4719F300BFE5866F0D6DA5E +C55E171A24D3B707EFA325D47F473764E99BC8B1108D815CF2ACADFA6C4663E8 +30855D673CE98AB78F5F829F7FA226AB57F07B3E7D4E7CE30ED3B7EB0D3035C5 +148DA8D9FA34483414FDA8E3DC9E6C479E3EEE9A11A0547FC9085FA4631AD19C +E936E0598E3197207FA7BB6E55CFD5EF72AEC12D9A9675241C7B00AD58FAF645 +1297991B5D01701E82228D0313FC7C66B263BC79ACDDF9AAC48A3CBF42B96E38 +583E1D059953076D68148DC8B6C9527B3A74CE7DEF788A11531F44120BDF0F61 +0B2F3ED94EEBCDE4ACD23834C242AA4314B9EF98E4BE72DB76EBDD0A028CEA9D +B4C38C1F2D24B8FDE686832FE96204552C820E45B6BAF0C3308742AE2E03218F +D1FBD73FA776E257C13AE8E592F7167AC957CE0A64DE81273E0C4492E02C45E7 +DA915CDBAB1CB1B3604C7828CB0CFD4F3E7B525EF5BBD4C99D8CAC485C56081C +4F14E27DD44C72777AB481BBAD9355F5952144E959AE6C15DCA8406EA14AAC75 +2A8D607F0140DA31B645D9514FBF0409FADF85DF37B02C0F8BEB4B41A900BA7D +98F84BBA101B38EF44072A53A8DC4E86AACC20855551292825AB73D5A605C335 +6C50E8D9D6D5589B8E5BCABF660BE1F9E2B25981FFA3B64426445C1DD407C126 +069D1F8A31455DF8CB5F1239785BA463E1DBA92AE81FCD0741B8C592A51DC137 +328580B7D8E7B9E097ADF9D48ABF0737595627610685B9125502A33F4ADDB177 +CABB9CB161969535E4281CD3F963A25604C29818D2BD35172C22A9044CB3B9E2 +C5DCEA9591E6ACDAC7531DA78DD11B3907638702D770B5D05AF44751A52C6CB9 +6A20D63FE74B9D5784EC3CBC6D856D366AA71CD83B947DDBF1C67BF6257E2124 +04DBF3FED2F6156C0A96D0D833A9A474B6334682CEF88503ACFB6C3A92FD326F +383931E04E285B6406797185FC551FC94B29C5AE791234998C89A2197500D5E2 +F8CABB4CB16DDD720DEA26A72DC170BF5BD70A0A76E503D96478C35E9A7FECD3 +F08FE5D49CDE67106DD656313EAAF6FC22E2FAEC103199A761A6DF15B7E5717A +CEC66D8E4B0A3E17E34EBC7C6907BA9A4EFD828D61195295C805FDF8BB820442 +7BCF4B548F09875CF2ECCE6BBC1A8B5E11B79453C6E0E595D21C5766896AF66E +BD5DB066BEAA86DCBC6DCF8F125C16D4342C874CF2786BECE6273CDDBD7C5C30 +F50A44F597B788A47C1C1C9C1F6F57F718222E5A81546D7B3516F123B5B45457 +D2CC1D6B69EE0D7459A95B96351D6399F9D6F9F20A2A37989C639C1051C44480 +25B0349697392CB0CDE9D8393F4BD06D57DC0C49978B132F3E9E04BC0631FCDD +FB2499EF53D7A84754B3ED08087AE62F4CABF923381ABE04204CF266C51D9A58 +A7F20898C8C563F6CA61FC82BD7ABB29FD8574402AC68BA4E10B1D4EBFDBBCF0 +D70F9E8A9B6D71762B7A94203EDCB9D7D914B550330F70CE022429AE06BF4638 +5E74C05BD4282CE2F01A350EA22CC2045F6A41ABC5844352E3E83236A51F3250 +33109126CC6022BCBB48E4A8D51D4D5CCFFE45642B4BB1BA8861BC052299C283 +C016DC15CE04773810ED40053617EEA6BBE379B90E675144919D56B4687D13CA +0A0F7849696C6CAFB20F6421F03645F5E8D0B667672A56C6ECE7A4E74A1D9B99 +01AF1FF7272EAD2D16C8B827ECA05871F066507AE94A9861A5C55B23D31F20C0 +13E3819427767105BA971D57EF4BDE96DD56BE7350552209D5BD5B4E4B269C31 +6D81A89477F287CD584531551E9B8D1FA0F8AA7249704FB5BBAEF8434F03D49B +2F51840447B74F65867980BD7EB9FEF2299A354763D566347EB6F4F8BD9BF98C +DDEF406D7C6B8696DFC81F7319E64F848DE6BDAE294A5B7875FCA9A10FA62203 +1F4C281BE1C1306A472AD0C8173F7D4972F8F31DC31E13C592C7768AD2CC999D +54AA69800E2DD016702FB5EFAE6377FC303A2C947D8A4DA71EAE9CE7D6B7D28D +2EBFF86E59ABB9BA8A3E19ADD4B590B8C18BE4FA931D2998DB030A24F0825F90 +C0E81BB5E6FC94078204AF5A0E5E4C0ABE29A6284E9C1975878040D1BDD5E78B +4B22268EDF8C1E7FFEC116AF536C769E4C22E8A8A0897E343FE147D83A3CB540 +49E0423E5F7764D62C437A2F27246177F9932A0B39DAA954DD9664649C5838B6 +6AD69111EB7576B68B367401BDA020E01832DBDDD7C1ED8FB42484B25FDCED83 +5832900B8E7B414573E49D93C290C9A4D9841CC45ACF8AE4494115EBC1233580 +02DF929FBAC4D799D83E3B8E1D4F99A815F4EF6E1C149DDDC0D1344F696E55B0 +E7A71702E7F0B691486C0A3E605C3B5E9E793C138F67DEFE329253507A038EE7 +4B41717FFFA1EC7A3F08E8952F5FA7A6F1EFABC12978F89C5C27113B61A63B70 +FF09CCF39DBAFEF07891FA5B0A4169C2BE6BFEF6E33F417E8E93AF443D3A98B6 +8983053F9108A266C4ADFBA2CF58CA4F18568876ADDD347102C971B3D9AE3BC9 +1F6E9190C83622B2B617CB3848359F66459C4CE2B592BCEC2379948FB7072DFE +FF12F35C1CA44FB42471067AFB1348ACB5EFC53BE2D178AD98C19B1ABFC82261 +55199EDF819D6DCD3039A06042B08ED04444890F9881ADDE8AEC63E44CD60339 +B32BA295041C610382C30D48F44C58961EA4EB78A4E6006D019D288C78E53B3C +1EFD0ACAE23A191088B575B31F173804DDE62FA57E3AC8E735ECD8E825EA5439 +58FA2D539D3299B72D54283FD35AEFE3A7684A322FB59A6E2CE290B52DBAFFD1 +A6507F2D1B77964B204C4DE65C2FC0B56675953C7CCDB781CAEBB8FCB0CCE665 +A4A5356BAFB45C85251468AC5A849F80CE6817F8E54C7D9A5D37077A6F3C882E +0ABFD138E428AF836F46053BA580BC9DA3DBB59D4347C6AC0F647A3B2DAA6D64 +D908EDE41A104221AC6868DDF215B0BE2AD0FA23D4384A096E52FBC77893CC1B +F0DBBB74456D2A2CEADD7D2C15B67C9E8E2A0BFF58138A19DE93AF4360135329 +0350625CCB5087F6251E5D6026A3BF4B66CEC687EB92880EA06D6FF07E092B99 +A956FD6547ED2723951C059255C6A7DE6C3B04E4DCF4C3ACA3090C593F23508D +832D3FEB1952022EC3AD8599FAE05DD1D04757E4EF9182AEC655908BA65CA4B9 +C7469AAFE0666F50E2C12C92B38FB3B96EE6BD3CD544DE71D777B3DAF4C41901 +A00188AE55925FB556B5879A99BC8FE5F4160789DC81A673AB4D1EA44A152A54 +833BCF7DA2EDBAD60936A0AEB95AB9ABCB99A631B22ABDA9DD1F3887D7BC9A27 +8E9076F7A5B497B21633293D17324DF57D942611D3C14B16717467A46930452B +43E0F1B4D852FE449AE78DEF75F0F2492A0BEB843E4FA7BCED98373B60F6836A +260E6EE7279BEDC8A06DEF9DAA85B68E973437395A129AA21714CEAF3D8D7495 +805B7894DA3722FC8725A73C8ED3E944D181A0A4BB139163C7EB52423561C23B +246313566BE9C0A10C5D224EBB5C059036F223D2AD876728E6E97E21075B997A +66B81E30A194F833158E1BEEA85D3BAFF0184B211B282D1C41FAE75BF1018DAF +F04F5488A36C3C5E9A2BD0C014E63D083E8D67E5930B4FEAA2884B667CEFF2B4 +7842F46D21384851C234758ABF1E16C006BB5FDC4E47659332FD3334B893838D +E7CF74098056449B5E4497A7863C8A5AE04D438679CDC969EE8CD5D9C8B3CFA1 +C0D839BA049EDF1DE2B3B84FD745C3ABF9B97962881BFC1A26CB2FB3BC9EFD0C +276E5E4B9AF14816B2F956DCD345223C1CC6C7EADC0A0DEE7CF39CFB9BC99E3B +7185A9A23B3BDF2F8C76291AF09F2CB32F9CCE9283744968421066FF8E6E016B +D201E9699337B9B7FFB8779C0D1B39141EC819010BB85E21C5389FDA571D0574 +A95469B2453E03F19178FD505896314F4FBF6EB25FB217A6E72908055A1AFD83 +4882BCF7504B429886BFBA89FF69642BEE40F139FF95B5D6F187FE9E85A8AF7C +AA46766813E3094DE8B05FB69B85A817F7AA397839D951CED82A01992336D7FF +D18F2BF0B652C0AD45EB0CF5A167D8B04CA8BCE7A579D2C41CCF495EB10559B2 +1DC1522E227850725BDDE0D7CC5C4782218865625F1E74892837874E4EA3D654 +45A115D129B4753BAA43F37B5B5937684A454F8ED536D637BA5950D74BECB9F1 +71C3BC5327C3F322692F16774B36C37F6D22109F0B60955AE455197908EF244B +FA907926C85BF42040CCA53D9F4352DE14DA71223822AED1F9A90A9B40656DAF +D10BB6C939EB45032364FBDBF9F8C8CEE91F3BAA30F5FF978B031621730A0FC0 +75AB3BAA9F2C3A584BC01F4F9E7000C3C9FF5A0F353DDE890E03959B5C0DC8DC +570983598691770197973CD43DEDD7D13ECE1AE6DFBB554B139ACC4A5D01F6CD +EBF15181EC3D3F0D54C6988E79213B32BBA1BD8596027B72A8D5911B83B1043B +BFB2FBCFE8F591BB3BEB0FBE0A39B7A88257E598FFAFD97837E16FC8162F653D +53768833844BD7CE3B3C51E7C9301173EE092B09AEA3169A14AA01C19BD32BB7 +61FE5D878ABEAF9893CB043C3DB4FE103739BED23B688B20515EC60DEAD17910 +AB3E9F949D2E5964882B5B10E6A9CDA13034EEC9C05C354CA2AE783855D9CB13 +79C4270847E736F5582245D8FD1B9410AD89FF57AB89F26AC9E8FC3CD7D1D0FF +5D164F54C465A72E55D58D3E761AD12D51C87E2967FE2998E95DF4E3B1D82784 +F59530432701CFDBBE6491F976BE63FC73AC27EBDAFF496542B9CBF51F113D06 +CC00C8F67CEA5FADA6340A3D052668E851BCC66CA5C2F420568B81FF1AE2628C +19F47440FE2557D6A789DEAE4C73C38918EE62D7A58054EB9952E2B4B8851D3D +665A8B133A4E185FC622D4C23978FEFEFD4A719A0C045BE7F73D6A817A9F54C9 +7D50715C67F7926F3F5630148DE144FD1016FECFB7F4C06AD433D4BB9C726BD2 +7B25BE0B1B1AB4FFC5FBA3863BE4B665270776D53F221CC3012A87CCBFC46186 +E2216AC623337D0E27D3A873DA40CBB7FF3C1E8B67A1DF6C8684ABD43ADAA3F3 +8010D0ABD67EAEBF5E226774493376A5A4346EF4DD7DA01E9FA3FDDCAA922899 +6EE155C5A927A2C718012FAFE57B6EDA37FDBB0F810F6608E34B324B2E5D1C29 +02704C612E7470A253FA3138C992748F4E42EAD79132C5D213E952077FEE0A88 +4BC9F8BF009192E845DD4DB1315E944FDAF71CFA7A1450E42ED14A845D78BC73 +DC6660EC29BE2120C2CB367DA4AAC0E9B6D4D4B92E05C6AB743BA5ADCA509D14 +6DBDE7715EDCAA1D1420BCFBD684A4915CA82099CE6F5DAB44C8ADF9FCF9A060 +8FC40E9A82C0302BCE230CB22D82E217760D55A27CA40C58C025DF4CC1D9E5DE +08A482FA7FE867F30F9FFCCBE7EFC36D0E2A995F8C6339FCB532F69DA58D8EFE +657465E914C702779B626C36EEDC5A34FD32B8740235B57B6B0DEE2E3E2848DE +078C425A78EB0F4AF4F0BC1113FFF1999B361A00637614349E23782A7D9CF57D +C57C54985B7B782814689FA04B39DD9F5CDDFCD96D9B4DAED6036E6FF95209A3 +87B136032CAF463729DDBCF736F496B38C4CB6E701776DFAEDE48A31CF082938 +295CC90D8D862F6E1A561DF0689D1018E4D84754A840049BC462D52D7E66A0CD +538DFBBFFDC37C32BB08725C8C00D2E10C8614638C7EEEBAB209C8868023BF3C +8001E9166209F0259F2F964B86C635098FC987E241568E09971FC44F62F1B81E +AC9F3656CBCAD6F929FB62062491BBA650B45D606743B92919C284BE52D8BD46 +1ADC9E4089752F7BC66A06743675B4BBBE2CDCD6DA08E3871FE16321E067A881 +DA3E9ACAB6767426BE9BFE7463C4E22F05A7F5F5A037C822711958CC5167411C +E28BBF5CEE22DF1B41FEADA4F7BF0200E605C3FA51676BB1275E32A253F34F4B +44CAA1EF8D26C49617536C25CDACF169EF87F1A0A491FD8118EB4DB0A6809181 +CF887941AB9B21AFDE0092AD49E7526E01BB90A59D85F0AC08E72C92123B05FF +8B94D1A63CDB90701BE7823AA0B21B622618739FDAE5066FB2692BEB1E9D9946 +CD2B3D842BF7C012F095A6F683F9D3F6A3CA0ED35AB4650BDF3D44D94EEA5FAB +648DD9B8324C2DAAF1D100499805BDC66497D44964FFBB311EC47B623B058709 +7727F06C1467AC260960B41EDE61C074D4A4A03D2B9B42E9D7DD4AFBA121D3A5 +140D2EDF369CD59273FDE0BBCA0BFECB7561F59FF1C444D69278AB164C699E9F +8C544F9DD97AAAE90AF1B55B38CEEA1E57DC9A40921AFED1F5B9EC874CB0DB8F +2C32DEBDEACAA05A465BD16CD30964E7B74A1B97E387467585AF5E8C93262D54 +1C42D2FABBA1BD4E341D899D4B95008BE831209B86CF848338C071D44AA36411 +F8184B65F5171C2CAADC46F6FCD7E1AE56B4B4C29043C0FF2998E5B704C7AD44 +B533E76D8A36463B13F8E23C0FB7F1925ED2AA3FB6B9E37C544F6149CAF7DE28 +0A1C6F605489DE91F4594F785E2C3C38E1A214D3DF66341EF1813F42D83A7C40 +92C8B8CD29ACAB9A5B102333C65F09F672C407BF119FFD34C7E9C8E4AAF63811 +7E13D9CFCCD65490DC433D3D75252539E799DAEB71FE0C5DACB9E06966318593 +52C995027950AC1A273DC4C097AA65C783391559661EF66294A51067CB68ABF2 +18E7A068DA6D67AD0392596A10C13F8135F5B197DC5D85DC5D7F376BA954EBBB +5B08D1D43FD6BCD32DAAE14F12001DD35DAB318AA252FC99332081821F48E494 +0570E7D1076E7C27DF29D684D7D8F61DDBBEBF138177ED20F40FE68DFDEB382D +A5511FA980BA7192CB67573E5F9649A3BF9304FE8BF46DEBAC4A81DA1E3287E0 +1FD5CE22BD1BE7E5BC2D4755FE929CFC83414B6668C98056B1B6648858945C3F +E0F67A827D3C27C1BE54A5AFD9A890D139CDF381CDC020DA73CBF69DE7F66E8D +2E14A3CE69D3C83E2CDFFC05AE6764C39D162CF0C303AD931FAAFDF0D9E3A5AC +EE8D4979E615FE6597BCE9249D4359DFF5533D448888FF1BC9322C11A0C51425 +E16F32670D48D0CF5B33B00B0E0504C002A40D6B7388C4F08F2AE68FA24EB061 +F9680D5F1D53FF6EF77608626ABAA805E8A177AB00A0B45F0B143ED0108FBE3A +80601B50211B43467584EF2EE44E5C6801D10D7F21B9D87492D4A3B559CEB364 +B2A2DD8E53FC2B11D1BB860B0C12BFD2AA94A8E2B331D6E4BDDFDD98B9140345 +AC3BB09686710F93B84143C05566C94DB4065107FC135B457AE6DE0959887927 +0A8A4EB0AAD916C1D2E65885419B7B80D2608C9157DA5E92346CC08B6ABFD713 +417B26C52058AAA83CE9266461C8C7C9C64E2C452618A1365D9A9C7DF70F46B8 +CC3FF2E35EE2B7CDE73D387231F1A4071D82A47C4B72B9F4982B62EC02BC26A4 +6F1BB23E4CC157B89BF687DD7C884569EBE64FDD89CC273D1DDBA4920E10F9D4 +AA587B3BE59BE11A56DFA4D0C3A0B71E060F27C2511FAC693CC6190874F9DB55 +42D0F9BB3F1811D6D116E10707943D9E01F9AA02AB82634A47BE76E9074A5E2D +40584F8BF2570CF2E6A09BC377D668DAF5B9D485E19476F09D636F122AC09503 +3765785B4D9793D21B50459E242D268F1A8B80B1D34C1DA5E7F8B05676A0123C +C9692D1007D39709937B6FB7889CDB5392FCE452E43F9A1EF57B88F381352148 +14E9A2513133B401068F9915926BF7AC51919E88EA7F704B8DB55091B41ED298 +2ABD7781B5D57818C080BA49BBC0F7C8CF3A192D72F2B190B062F8CED619CAA0 +B4865E31F62D8EC56673860F81E313BD1948147A7F6E995A75CB28D4E0552B87 +55EEC62AE5C9FAE3533AA0E8B96BCB76A8E3E15F2F12E9AD6AFB64093A50FF0C +98E70CE56B42B5A3073608E933FE9D1EAFD5D1166913F874B1E7FD3BE6FC3114 +4E79906F89BEC10335B2D5CB87D9432624D4BA2BC3C0E1E6C4FB456E69FE4546 +9E9609A989F2A4CDC9A91877FA7818AAC8DB4F087D56876EB2C8E4E7EE9A9CF8 +15F0DBD4A8A71904D25B8C015BE299ECA2045613DD0C54F8173FEEA38F2C1CFE +30C60F83FDFF866001347BB1861EEE72620ED0F8A8D1AE60080E4FF246C14819 +7F84845117657D5D403257FAAB31750D7D65EBD15EF09861CBC04F13FAE2019A +9BD4C929E68C1EBBA6FE702B748B00DAA6BE91B7223D8DB1E5C642F2BBFEE372 +E5D818555338EE46502ECDA319433BBE94DF3F0C6AEADC2FF9186B0CAE4DC27B +46B2C3A37D00C0725AF301F13BCF4B5B8AF453308F0B55D9E435138C6099B6CC +2376D5480EA5B556425318F1FBA267DB3988C2D0DEF86F10DF8256FC0148CB09 +87D0FD9D13A82B2BC328B7F7CC7CA783F97AE3FA36B6DB42D3EF416D1535BB8C +560906B44EDE2EA50A0351597C2A8489E43467B8436B35B2EDF91A5C572F0232 +5F20658D1B3150628A182081CA69BF0D751EB13D33F585E1BE39B6E5AE4F1062 +7B9D6D9530CE4A37400D90B000FAEC76076D989E2A83B95719F529DE0D2D2D4F +48C9BB0C2C93CADF703326254312067792D537C4C79D7A1BCCB92229FE5BAB11 +C456FAA4626EC3861BE859A906258930A80255B3D08E5F9E4E86385C00C5C5A2 +F47CC82E7636F29737A12F8FF140D04A5A86F02F906A1AD1DC898614D3E817DF +F29267010B7CEA70B1CD1D943E9B5AE2D5A48BE6689FB749343C4285B43BB2B0 +8B3FC1CC66A8AA7B23D90CE25279DE770224A3A165798A6B78174B90F05775D5 +BF1CC83DEB893E605542AC28D0763DF8B4BD23F7EABB4BD0DFF00DD499A89949 +7106804A4F82B49DD596C761F227DDE94405B674462CB665EAD6D97FB5DA5702 +979377470BE9AB10BC585E48A843B553A28E6BB249B7872324B870945FA1CAC6 +5D45A4D5BB8079CB19A98B91DBACAC73955D0BA8604C224942869DDEB7082F78 +CE525AB4C9F13BFA6A03D9B68C7B93C3B880EFC2AE2F7CA6CBDA2D14965293C9 +52AB492F6AD0860E2AFB95BEB49D72F6A012E7BB823F757245770FB437948D31 +9C870466A76F7B3A64B35254A1E204AC01A7E95B9474A910885D934B82D46A25 +94ECAA08EAB7A9BD981B497D330F065A8F32ED38CEE49CC553C0A01B296E756C +9A73D70DA5E667EDBBE4A4854F05D48B76F06FA820EB4E7CB78856EA24F42DE1 +3F5FFCEC0EFF1845F72E2A9BCDEE2591826EFB765DD110855A0CAEF92C10C539 +ED4758A298F222ADED706BF6A7C91C44E314419F7EC4CFF3C3F230E6161EC992 +B0EAACD7BBD525AE205F87770EC29523C4350BE005FE17BC74F2D77EE0639060 +C2849112DF47B0D9978BFA214AF0DA01E60BF4B773DBD3BB38454C183C9DF5CE +D25BD3A7EA206C05BC996CA11D7181D67AFEC635BF3341FB045FC02A4FB98D10 +DE4676615FF144B5BBC1044313E14AB345C753AB2123C93F8222AC713DD22F7A +8E1B8EFBDB3007BE5B70EAFF2499C3F1D9E6CF51176B1FFBA9872B272610D5B6 +31724240D239EEA920506B99B971B047C824404E0D997F1FCF97D0F43010E762 +6BC2A96AE37228029A7507E37BE422C0DC325FE65DE05711C3F5F67EC2CA801E +CAFDCEFA5EAD55A2BE9E8A9CCECC48C77B48BE0AEA09A3252D68899E057835E3 +EF47D31258AB9C120853DCD0094FEDFFEBF389BD4691E09CF1F14DE9F589290E +51AA0468A61DA947C4005B49F959DE57AD89B85EBDF5FAB9219E7EB073EBB7BA +572272D35AB8ADE64CA21B856D46073F03676A59E85A07139A0104B70F4DA3D3 +27276A84D3FCF2F02E1E8A580D1F9C20B51CF84389CFA474AE42490B0746754E +1FF5BB0542FABE64AE8CBEBA0A2976CD88D210FA818B8A6C16AAD774D4FDB8F2 +2919FBD70473198A0F9EAA336E9942F854D2565B9F06918D2608A41B18232B45 +2EBDEF411ECF115E893F4CB1681A151960B7BB1B6231BAEDC8679BFA87B56C47 +78A5030C697DEB344B7455AA538DAD6C50F51A5D87324AC2F1B0A49586444767 +781FB7B912531461ED01518BAF23B61E7457BED5C8B564191542F3965B04A06C +8C6A8690AF59E3CE0040DBD54DCB0D330816DCE29F245773339B8B1EEE7787D1 +44713316D303CCE52EF07CF81ECC4AD87E41F99373197835A3EA5CE46D522477 +9908FC3CD8B0DED0583DD8EE6E6B2314DFBCC27B +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark +%%EndFont +%%BeginFont: CMBX10 +%!PS-AdobeFont-1.1: CMBX10 1.00B +%%CreationDate: 1992 Feb 19 19:54:06 +% Copyright (C) 1997 American Mathematical Society. All Rights Reserved. +11 dict begin +/FontInfo 7 dict dup begin +/version (1.00B) readonly def +/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def +/FullName (CMBX10) readonly def +/FamilyName (Computer Modern) readonly def +/Weight (Bold) readonly def +/ItalicAngle 0 def +/isFixedPitch false def +end readonly def +/FontName /CMBX10 def +/PaintType 0 def +/FontType 1 def +/FontMatrix [0.001 0 0 0.001 0 0] readonly def +/Encoding 256 array +0 1 255 {1 index exch /.notdef put} for +dup 11 /ff put +dup 12 /fi put +dup 13 /fl put +dup 45 /hyphen put +dup 46 /period put +dup 47 /slash put +dup 49 /one put +dup 50 /two put +dup 51 /three put +dup 52 /four put +dup 53 /five put +dup 54 /six put +dup 55 /seven put +dup 57 /nine put +dup 65 /A put +dup 66 /B put +dup 67 /C put +dup 68 /D put +dup 69 /E put +dup 70 /F put +dup 71 /G put +dup 73 /I put +dup 76 /L put +dup 77 /M put +dup 78 /N put +dup 79 /O put +dup 80 /P put +dup 81 /Q put +dup 82 /R put +dup 83 /S put +dup 84 /T put +dup 85 /U put +dup 86 /V put +dup 87 /W put +dup 89 /Y put +dup 97 /a put +dup 98 /b put +dup 99 /c put +dup 100 /d put +dup 101 /e put +dup 102 /f put +dup 103 /g put +dup 104 /h put +dup 105 /i put +dup 107 /k put +dup 108 /l put +dup 109 /m put +dup 110 /n put +dup 111 /o put +dup 112 /p put +dup 113 /q put +dup 114 /r put +dup 115 /s put +dup 116 /t put +dup 117 /u put +dup 118 /v put +dup 120 /x put +dup 121 /y put +dup 122 /z put +dup 123 /endash put +readonly def +/FontBBox{-301 -250 1164 946}readonly def +currentdict end +currentfile eexec +D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891 +016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171 +9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F +D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758 +469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8 +2BDBF16FBC7512FAA308A093FE5F00F963068B8B731A88D7740B0DDAED1B3F82 +7DB9DFB4372D3935C286E39EE7AC9FB6A9B5CE4D2FAE1BC0E55AE02BFC464378 +77B9F65C23E3BAB41EFAE344DDC9AB1B3CCBC0618290D83DC756F9D5BEFECB18 +2DB0E39997F264D408BD076F65A50E7E94C9C88D849AB2E92005CFA316ACCD91 +FF524AAD7262B10351C50EBAD08FB4CD55D2E369F6E836C82C591606E1E5C73F +DE3FA3CAD272C67C6CBF43B66FE4B8677DAFEEA19288428D07FEB1F4001BAA68 +7AAD6DDBE432714E799CFA49D8A1A128F32E8B280524BC8041F1E64ECE4053C4 +9F0AEC699A75B827002E9F95826DB3F643338F858011008E338A899020962176 +CF66A62E3AEF046D91C88C87DEB03CE6CCDF4FB651990F0E86D17409F121773D +6877DF0085DFB269A3C07AA6660419BD0F0EF3C53DA2318BA1860AB34E28BAC6 +E82DDB1C43E5203AC9DF9277098F2E42C0F7BD03C6D90B629DE97730245B8E8E +8903B9225098079C55A37E4E59AE2A9E36B6349FA2C09BB1F5F4433E4EEFC75E +3F9830EB085E7E6FBE2666AC5A398C2DF228062ACF9FCA5656390A15837C4A99 +EC3740D873CFEF2E248B44CA134693A782594DD0692B4DBF1F16C4CDECA692C4 +0E44FDBEF704101118BC53575BF22731E7F7717934AD715AC33B5D3679B784C9 +4046E6CD3C0AD80ED1F65626B14E33CFDA6EB2825DC444FA6209615BC08173FF +1805BDFCCA4B11F50D6BD483FD8639F9E8D0245B463D65A0F12C26C8A8EE2910 +757696C3F13144D8EA5649816AAD61A949C3A723ABB585990593F20A35CD6B7E +0FA0AD8551CEE41F61924DC36A464A10A1B14C33FAFB04862E30C66C1BC55665 +6D07D93B8C0D596E109EE2B1AAB479F7FAA35279ADB468A624BE26D527BFF5ED +E067598E1B8B78188FA4BCFB0B51692D07B0BEBB930C6F0997B437E2C51B876B +61A563A2673932C2045833FAA35DB22ADE12102335D5DC734AE3AC5EEE6658D7 +92EB62131E1DFBA441F53EFF9021D9D4C491F26BE8F54C61165CAD778CE8695C +EEAF70E3B20C64D4C2B34A084B5770BAB2A974E898F62BFE90F132A37E2DCA4F +43E13DB13C94DFA8ECE2B7374827AE168634FA007F8981ADA046CED3448BF453 +FCD9A4F194FA648F9FC0971734BB69CB73439CB0DD021D44A7C11BF295E81733 +4DFBA460FF3D654F9FB337E99E6D66FBA87A817EB9CA1536C84833870E3626DA +55D48DE850D3E6F6B29DA0E7C9D681283586F208DB8D58042E3A7CE55BE84822 +C98237911453E479EAB65AFEBA3F61A763B40E74535BE56C9D8D06DDF9441741 +5C9D9D917439368736619717FAB4F06E2C329AE0BA411F3FD522D9C33AD8369B +D7DCC9DF993778482F35F965973DE876FA19E109AA198A00658AB3F0D8E3DDD1 +08A573F2D525202EDF2C3F52D34947E0964D0E8E89F6043C0D2C9C394D2615D3 +5E1E123BD76D4E60AC8600305C844091278B74194D938A402F66FCF1A12B17FB +64C1F829392A4308CA536545C02DD6D3F4EAA9260F62719F5051781F56C6C079 +9FC3AFAF5E973ED7F059ADB6655BEF2710A5A8CDC905404F26C04988D38198AD +377F5FD879E3F511D5BBA61EF3A7313971AA8878E61C6176FEC09C92CAB6B6F7 +9D4494A95C08CC426800B049B12EA5EB668D4E321590DC69C752CFC0EBB51703 +430B1D30B335F948102D4761972FCBD77119425F375565923E68A114C25D3B5B +4D020F90F467614A113E3F11BB1215EA2DFFE4D82E847DC7161B360AAAFB09D6 +0C505E24D1FB30F9831F1A0ABA3EC1427D7C4310523B30CCA64668329ADDD369 +BC652849083A43B1AB78567467BD8E6F9BE7BE71C0A01AC7994C36B9EAEDEA11 +15846E0E91F5207ACED1EA72EB570656B95F323B984C36A7ECA589A25CD8977E +083D56E26973779B1EC4B757074564193231D967A978433C254A96AF9565FC1B +E303AB1147403E4F7F86400F9913449F59ED573A530FEAD1E8834CE2899664CA +7DAF1E1C2FAB4698E28B99F81ABDAB12E119A76AF48619DC24CB9A1A8115CF0D +D497388553FFF051890ACEC249A364C1936C2084A70A7FFA1E46552280182DA3 +AC45F303AC495C5D85F5543B1C872FE9AA515F68E3BF50747FCCBCF1C50AAC34 +DF6C7894EC4EDB18254EE7C5039D50F5FB9B42ACAD360EA047823B7D485FA95A +82026B58FFADFF4D4B38B1893A855B4C764552FD199CC9AD11D7A028140C77DF +43E91706ADA1B5B7C7B719C10C5A1B5B3D52CA5666CB67B37870A6C57B2D52DF +0E0EA39BE95F3440352F7D9A1C3E6D85E03E615A60A0C94B72B75EF14ABAEBF7 +7BECCFD65464C0535E8BA881654D023C202FE24769259E20C2DF579A8C1E5ABC +2BC115941504778CE68399E218BDFBFE6A02944BE236A3C3B522C0CC6CBB15DA +7FF83A5661CD26A842641D5B25876D32D2C06115DE320EC6E61FBB7439955833 +604D82E1ED89105807B9C3C17866226360EF6ADB7E7DEAAC7FDBDFDD7F14F423 +34BBA62DF1CE26C2D12814E330DFFEAAF4075574C306FDB236068AD315CE0741 +BBE9C2A588E57146BF9081C556AE1C803E7EF02287489432B3EC3376BD946A16 +9EE9ED30B223DCAA5E41F4D0D2DF54F51A18A46DC882D3F0685819E0A923F2EB +AD5EACD7ACEFF738DDF2C69A774CFA497C0342F74E34E3AA12EC97692223965A +B566F1C1DC629B4BEA682A9A62DD3400349AC6A08A9A85773267A17945C07758 +906A2718F530D6963BA2AD50514EA2968E2B1E1529477DBBF9D7E013220C3427 +A6169C8ADE30FDF4A1C881C37FD2C11267CEBC306CCAC7C4E357E67B27F77098 +C325A971120C3ED19C28D30548C98A69A949C4EC75D454A205EC904E8D393ECF +5A96A4E558927840A2525000E4424770D9B8C3F70124C96041E82F0EEF66F9A0 +23BB6EAB38E3D7935C0F1E836F8182FC525C41129A493548CEA9E6550F476746 +473D419BBB710EF961EF827E3C70311BC976019FD45509594A805372D57FCA9A +57B73AEAD5633FD305C2B2BC952F1FF592E3605FF20871B4C8A2DEF33ADAA91A +0D6035D8350AF9071FF8F71F9BE291FEF13692F2281AF533AEC6D7F05A1CA1F6 +CD0177E68C220D3CFDCEC5D196EB0CF334AF04EBF902A491D5075C553C74BC8D +E99B4A5631068EA237A311C09A5286386B4C41264E6F295227FFBB796EC4B8BE +01A6D6B1D797CECCBCDE5F18210C6CCE426A13F4316D317DD427C7D7C2EC2966 +CD6D3B2AD989CC3D74A727A9A6E1CAA7CF95C3EB6B247AFAFEC59389964CBF7B +6FAB84821FD1DF62817CBE24307242AEAF0252EA316CC0F516C4D6F83BBE8998 +EB714C412E47DFBC27243930CB2B4538946C96268E54761CA1488AFCB5585844 +FC460476975C2B31A2C1C87076A6CEA7D7E02B7C753256FFEDCE205BE4E3FF7E +7499AD82C5BDBE95F2FFA43D45BFB7AA94CE43559B1D9B917082030893FAC3E8 +8A6BF3D8DD6B8EF3A773BE63287908CE8C429CBC50C2122D1B505CE2E8944C8C +7C4E61E4E483A30C0445856706A20B4D7F4C02E2E4A7A5CF1E4CD5216A376A51 +76230CC41AC5F32AD189E4744E38AA5A93A6BD14D4F0745AF6052B16A33BBA57 +30369AF4FD47C26BBFD4CCEAA42B4EB9ACF34A47E61072215E23CAC5A8B1D8FF +258A343C1DBF8E38700193A8DAE152AF4F5CA9994600886A3C460DBAA2EA46FA +2300AD7F68A799D59D6BF481EC566FB71063A2F6D758E76CC07CA434F8444FEF +58191D0651CBCF803805AE48A442CA880AAAA2E4C398A39CF2D920C770E6EF39 +9C28CC8DA0917506E7AB34C2DECD7D0511F429C6BA42F75DF62093750676AEC4 +F5CA35799ABCC557C5DD1233F50BC4F798056D18A35E394ACCE3391A0FC2004F +65F157AEB3EDA0BE4B5634650C505A0249B35BC879771647C05BE3AC020D1D26 +E65DD013635CA9229C4C9362D87DCBEA4B88EA12C787DBA00D1B6050FC5A144B +A6193A6394A654FAB40CC12C216726296FF3659D88EBE18DDD3BB16E6C976BF6 +0F01D9ADB262DAE09AD0822B042A33BB939939361F2D1247E5059766D0FA9104 +37E3183B40926E8C126C1633D71A0A4B2D4B54B2E16263C7418B3BAD891233A6 +978051A886D44343500F07C8BC6EA961E11F2BC449A78C3B5B5587D0197096AC +FD066733FE869503D662993117CB9A61E60F353901B9AF4EC6A3C7D5B366A0A6 +772DBF8A2579302BF6D1408D0CAC1379DDC0744DCD8BCC01880969FD1869E7FE +B76AC1475E3452530AB953B3674C5222F9A97A91E5BC5E6CF58E3F5E5E80BF6F +C085F6A87C6E6FA510ADAF3E60BF2142CDA3C14544D0E3D4A24A975A293C4AEA +89F0F39F226631E2A00C68748A661BA84651702ED474847F6311BD70FE580530 +28002B2FCD9BCE6E1BB4AEA57FAE770E3A8D80FC8DA4FB93186FA641CD07CDAE +8C751DCEFD693D67B4D70B30E75B0C632E4D1404FE906053B5EB5619D3F858DC +8CA13B5B5670DEED71787A81392D2D6FE28C4BC53D8EF7C364D52422D6E495B4 +8A1755E6D02F493C50790D6F23CFFE55303B9239F2445439527E9DD0B6469612 +B496479EFE1D12FEFFFBA7FCAD33F98BED0CF6A58A6BDC7D7E376D57C0C7DAA8 +2D7DBE6C378D0795301032AA3546391F294435EC95C71C735AEF116BE5A9B4C6 +264CBAD7921C28E1FD2F8AC50A490BF357926BFBA67319FD65918E19CE1B8E90 +FDCC36A6D568DC017D580B3A3B7EB545FB57C3EA9FD510028DB58A28EED739A9 +AA0229E8C3C60CB0589D76DE849DCB343D8A73D851784B74AFA1DA04DE613C79 +9C6A15B7DA1028387581B6C796FED3FD340BF81A3BC189A8A9B80E1731D307A1 +74B91B562264AB4456B07972A52905B7E575BC5CADF06FA463019FDB3B943E5B +940A52D110B090777AC1A303CEF1CFC68883822C50C42160F50ED91DCC1E5978 +0A187A2AD94DCBA34D7481FC0429172B34648037787928770D1EC95C0E0E5AD7 +EE10CD012CE67FE7F9DB921165FE03F9C6C10F307EACC687E33E4E69A67C5220 +C023F8B9F0287282827A38452E1D30D947215F2969289D1DF3C67AED6C8EC488 +2AA9D8C6B49A26BBFACF50E66DC91DE5E59C79852C5247EB2D50D816AE703B54 +D252FB14BD11C750A32A3619E069F62B944584947265CBE922B5BF109BF9BE4F +981B77EA4CBEB3E27C75CCF73A893ECB44BA310FABBA15C9517325A102E048F6 +E843E601D52F1C64CDF949405EB01A942B6D8AB2BB4396F9D53A27858F9AF4AC +9D618A8F370C8B87ADAAB6744EB75D83CD1ADD838EF46509FD585FC3B6218C6F +408194725373A1D95BF2C5068C895EC6A8983C167443B3F0BAA95349A45C9692 +69B662C74B84BB3C0DED37F110788DB3FB2872A961BE39B003D21ED7636E8463 +B81D6E3FD3018A8E7533C9D2E7D535EA1215E6A752C67A9B3F91F007614A8893 +874AD09425C3F12EEAFCCB99E74EFB509736DFA1CFC2DA89D4C27D15EAEFF682 +5023F658BA969E3738EBFD2A5F9CF78ECEEDA79FF9AF6E52C6FD41AE6647585E +20132F668580B8C1AADCDDFCADDC7DF36610B6982246D36F46073CBEECCC7C6F +599597F72D2D013F81B2BEF7009682223B0F8008FC3815722ECEC2335144D7C7 +1D8C891B2080E3A3E1D7E2F06207CA05620EDEAEEA71CDD03EE6C78582FC1306 +6B9F74DDC5061963F5C930A855286745DFFFF6D44A747776B3DB55923743CA43 +7F56E25961D5DBFEA6EF9944D694F0B253CD249A805DEA0ED29A6773E4E35C12 +C35CA856CF45B5AD965E8A37820CB9E5EF03972F0CCC5461CC2968940E3AB451 +0B7660EBE794E55F6AF1F4EE7A9D6C4F70A6D4DC66DB29C0C156462F8E4001CB +5FD2BA4C8A1F86D0AAECE6F1C1300DC41F5EEF36D36875EDAED5C1A1B98C22D0 +F32F3D6DEEA5F122CA9FFC3897A044E1CEB9D2D3EA7F147FAAA1B6FFF7D18426 +C1CBAFFFDDD6A1692DB6F655ABCCF783046C94441DD50628A197266ECEF86636 +650466B2903187B1E916A14316071AE2857EA11AA56D610E22BA88272E3BE593 +B2D53BC9343BFB42E9FBE46AC470B53912081438E5DCBEB1C036CC59B4F39E57 +23039FEADEDD178A083E12A1137F6F3C302EDB41A202919C549C2312F780D65E +AE8EC6D9A5D42929476889CBB2F5193158CE9F752A3FEBB3FF6CBE0489727D4C +149E4314F22E5FD43A471233CDF9825DC10793F0E2217CA73FC62153F897E21F +D74267C52E9CF159DC024AB37DF7D9F1144B0A3CCDD8F7211508FEC92946899B +239E854961747E07DBAD6B8B282003F745051A77ED70E82CBB21A1BA8AD019B2 +398D69DD9ADEAA014FD1FF1DDBD66C649BB03E66A47ADAAFF92E0A2BA3D090DB +F65B8C484B7B1D04F9B216B9FF8BF549319B6CA778DA51955B6FC472714BC86C +C6AF14BF4BCF0A443EC718A3A9025A4EC376533E251D9A51B2924FFD25A8F01F +864CE38F285FD50101DB9A3E75CE655B4BF51FD1DCDC69241174DF6B18BA8064 +3E5141DBBE569DE6194AEB569E450F31AFAB47FB29846FEA931D75057C7BB07F +680026911C45B65D8197FE6D6FDDC6383CDDFB9608D23E82432C8963151E5A75 +EFDEFFE33498AAD61F549305AE02D8FECE59BEEE8DE88FE989D2E33AA53D4D08 +4F6A15DACC403C151F0B73FD2ADF835CF0886A5D99BB1E1E2E98B0EBE122F18A +F6641509A4806D4F5C91D66EE801EA219D4B972655A7833CF72CDEABC87232A8 +3CECBA287F9034AC75C1A01DF83399E87EE416189B727DAD304E1F2BF7C6BEA7 +5FDDA4D7D4E310AEB0EB88C1F8E75A97DB494B85347E5F88F33E6EC2B4E1734D +AF732CFA70020D6665C383F7043ED66C39A7598AA85D7F21C2803F3F4B5246ED +B5E79A91AA885F64F401E6DFD30542324035D9C5C762FAF5C68B79EA0D38B676 +B1FBC058A3E9F1591E20B7565D0CE47C1413B74602E544E4E2A5CFFA27EF679A +B846FD21747041807CD911FFE95792828243BB985516B637779F857346211C7D +041957D384B7EE553D1CA18DDE4A3BEBD9534ACFAC84BC34A9AE092BB70994CA +67D69EB96F3FB4DDFDD4D00650A76357F54270CF34F93378B1B1CE5BB8EE84D0 +19403D93204A3BE35B636BD6A47FFF0DA0C80F52DD1728F3971D6F998CD65101 +2C8A6D2212F8A3305E6FA2D61AAD342DF8C7117A81B54BFE4B620EFFB2F936BC +FCED424305C6D391425CCDC0EDE6B8745E90F31F12C5ADC0FC7603380E9F2B38 +71B2175620A35301B1CD5C102600869261C07896A8445B7BD39F5EB7F4D4F2A9 +BE286A9A5942C11962645D82DE3C688D7DE4F94D10D9BAF9C8E391F61091EC85 +C73EC6866D701F7CC99BB0B44DBB076D6999B95251A18442DEC34D8D19ED2584 +EE2596435A8A4EF0DE46C8E4C4A07A04BF104ABFE1023D1F43192CFFFC474E2B +94FC025C0CFC3BA69BF352B152490BD46A2805184C048BDCB02F3FD2CD307B87 +85C1DA8D2A60C82EA68925D8902C22192E384B6A5F2C6710482179BD2B3BCDAC +F79CBF2DA3D7B51602C595948D9E1DB76B393307FE56C11E3015BF46E0B35E63 +490073854F9ACDDF89D0E3B3BB453EFC6375EA8C410F3110FF2A02178EC39777 +CF9102513DDB13DAE12CB2E0C4091C43BD903474DEDFC3BCC8843542E8CAD2E9 +6508C850713F1755BCB506A6FB3CB275E8B844E3DF6B62E6E17C0F5A88CE31F4 +D112228474E6B1AE069E0DF0DAAAF4E7E2898F6236E2A3EA4E93DB86DB863247 +2E77512BE0EB2DE0284C591FEDC21F99D24094B6AC43629D08DDBF12D0F7C4FC +0DF8448602F7D94E8011928633A159CB6E9EFCA54A8B0056B3E931C57EDF5BFE +871D6B772C1084B0B75F913F8752C8314093E33CAFA34BE9EF0D9B5343ACE66B +A72BE7C3506937A146D1E5F8729904C0B3B8EB9EB0A592CE376B7FFA90FBE94D +5F59352B8AFE3E402CFEFBF75FA1C20196222A85CC49124C982FB6894FC3AFDB +B99895371AD3CF6944EF3F291F2B8EBF129F146AA5A279532D1BD70B7C79E9BB +0E811911747A520C3E1BE5B7B629E2531AC3D409185871E1735F23F3BDB040AF +4824EF7FB3E32030B2858F01CA09123E4F4FA5E05B8F57C34830E21CAF084603 +AAE93BF1AB611E59D55922C70334C79AFA0A0F4723C7729F5AB621DE1884C3FF +56168C3C812E6B9FA4FFD98D9F1DE09D462206B90B59CD2C158FE3E6D5BA26F8 +FE0A1F14E1B4491C4F2A9221ED3E4B73CE4EE697AFF4C146E8EAE92FD271818E +FF1330BF26D80E7B018F4DA75A28B8D1A0E5AF48B766B4C4101B84021FD14B66 +539F72EC88B932C73FF43435AE096C7D860E45FE991BF59A1FAA188CC7781DA3 +7B6BD324BC92756FA18BB67AB9FF23428FBC4B194EB5369B6F2432F5C7660ADE +39C0E299C79F50E35FE18F436A0B5C841C3C1B5EDDE8A322BCD3763D5655A9DD +302B689AA70F31CB4D18CA10435C499E9C2A9C25B9943924AE642AD0E92AC7AC +A57737B9BA6A365749DFAFD5AF7BBC1B9412C73F4A8F9B8C8CD405DB48CD5E48 +FE49EE5FC8EA7CDA6A3243454F9904E3479088C4661297DADBBEF49F5EC8BF33 +4807CCC58561B84CCFE56010F75C3F91A4892911081CF2F838A8DE19DF9AC7DE +A666490D5DB64DB20A6918F660A53B9047EDA49A0C8F67FAC05183406EA60711 +DC91F2EFE67787BCBDC3150A5D6DEC73B5EB50FEEC33AAD6B08B22F231B12CF6 +1EF09B63640F3FC0527C54179E49355C991AD1A1A453623EE56F5D578BF628C3 +39F638BBD17C905D31FC46509EA428153D6FFB4D029AAB5A28623E9F6DDCD20E +9553A3C754B3C2F518C12993703E4FD08044630522BC2719721C6E8457F6300A +5DFC2C84E9F45F9A98AB2C9ACF75BB857357D9490F9ED4FA5BC3C57E020AC381 +A79D572201415245936F0A5A736C0BEBEADDB770CAEE53378352B2874897C58E +DF88076F73EC8965526AF9CDDF2836107AB0A10A11B2DC3A09FFE53453665105 +C4F77195DAE486867B47DAD79C37B6677A3F346375B6CB049B759459BA9A8F1E +B157788173DEBC3D4979B7C0C55ECC442DDF6C33DA0D83B2FC21101A7799430C +8C300090400ABAAA081A2FB34D75EEE19C91BFC2481086C364757C2C1B9D5178 +7D395738A48BD22023CB29425E6D809FA0EEC510DED243691A5FF62DC665E9FB +6B1CB03A404F56821A19FD4C813A26423B1418E324155B5E0FD66A364F7916FE +8DA49435E596403761EE8D1DBDA2330030EFA532B9E3ACCEDD9B0F879753B74C +60916D3647271CB2DB327A9B076D58EB84FBC4B405E4C4C2A8E0020839E58CE8 +985D6C7664886A4DCA581D67F06FAB46653AAF06F3FA43E66EC63E05F8B94FC0 +73B16252D57B007B88B6D815FA97C7B2E2F2FAE3ADF4B2B93ACD81376C369A42 +CF09D43BC0869C245C3F04AD6BA9167BD14D778C8AD2853FF8B5824A64033BC9 +7F9C84B8CC4F7D998421C5795947FACFC78F7EC7B4CBC12A6F395751CBA4CAD0 +BD92A096E5F76B2500658D0B01017CC20F0F4BB628117297D67A2304AFC38EFA +26E11A78C968BA4FA933123D2B6926BDC466BA3A9398D7AD6A420917038693B8 +8EBEFC7774E994F4B6C746FF40E2337AD2E045753CA003CCC118FB541A5CA386 +C34F0DE2B57A815914874EA88E426F6DEB0D20DAF055E9696EEB29CF74F14FE9 +15FC6B82C17C96900D382AE9656C823CE3EE7CF64E08613A308FDDD046E7D6AD +CC73028E734AB6A0CF0733EDCC50C1EA9D041F26528514427DE2F52AD91FB0CE +BE1FA00385752D3AC025DC27310364925DC54E000E8A488CB634FBCE4B6A959C +7F95965A6B028F546B65FF42E0CADD92DFAF55C23EDC6F083E0B373564701250 +5ABA7171FA8258B2EEFF62F0FCE3DA03C0EE0B0192C4E32CF0FD956768252F5D +0C8E9FED353314C26F3C8F220F969ADA76D4301177CA719B8F304BEEA2717E56 +C4FCEE82FE15FAC8477173925CF145104D9BB6B60BF962D16E522E67E792B3AD +CBDD1F19C0AAACAF613AA1FD18FC1783272150FDE3919583BC6CF13C62B75CE5 +90363EBF98C6B236824ADF29A6D6120A83AA402FC206C1B53AC3E56FF54E4072 +992B96B15EB3C09EEE64544C96B80F433E95B9DB53732CDF9079DE3E46108EC3 +A532B1FD301C10E9CFA5E1350477E1B802CB4694A86B1958BF77AF0440BDEA47 +7575534688505F2E695CE7E2266A3912D0704CE2540271801F66CAB5CF27F719 +B4D54AEBA9AD6CEB10A8C1F8385AC32F026F15471CF0C292200015CEB8836955 +B0CA14A5BEC504D0C05C3515B7D0C4FB0265F1087A0F56A6AF954E316902584A +E2F0499F48015C1BE0AD119B2ADE3D462EAD7FC6035963D37789929E16093D6E +EF8A5FD83D5841F89B68BD8C8F787DFE1122453CA22E8B596FB38E0C05CE4023 +21B7F755724506CBAC19414F1E3B7E1CCFCC20C5CEEB65C1E49742D13B946FBF +C4E98599B69B74B36C0B7FCACFC63EEC6BD9779F9783DF293EB77F57D89324F2 +FA76F4F4AD5A7F6B65421385F46C40544D530D32F43229BFC83580213A3D6128 +D0CE68CBA2EA766153BC10AA324589DA09F7DB7C766B8D91CCDF1FC4EBAECA13 +75714EDB323B7A91A0A716072ADB9F4A992D7BB51F0E033A408B137281119D31 +451523575C63154C32CA49B4BC97E80614A4A60FC55AFF3820B6795290A438CD +ACF562AE94A6502FB3F259EBCB6189C34F1BF74DCA2DA8D9C750E18224B7E332 +461A3A41B16C9ACC1D7A90353C104BA26821FC6A3BBA18221D06AEEC2C69E7CD +88961F18A48F6C215A61CCA7EED56E7D948BCFDC87187001275AAF88FF5E41BD +0C3E9302B362B5D21CA18DF6B3E7C776488F5B27637DBE9E547832AC91360853 +4D42B60BD7F7FEFDF6DB5F4C0AD2F9CE0769274645AF7D07A9E015738A9F2869 +7A610F927D024A2F3A2182B2D16F4A177BE44F118F758CD53682E5B1BF60D74E +48C56E41DC7B170CBC4DEBC07528983F5BA6852D8611FEB55F4E5969BC3EFCAA +039D388947052F0B6F54862F25F82E60F8AF4EC65F922252A711DEE0AA8C101E +6C6CD29AFB07374747DB5D1F1AF70C82078835E67F5950A72464D9D05DBF0BD2 +874C7E2AECC5AC0C5EEA58ED9C9828A1C3955AD17F71990C9F4200C428E35792 +4F6F7A7B9E185DFF52C637BC873636B4D856F86A67DF309130D0CF455762A680 +483842515002EE52ACCE89168E6FF5D88092653977519970076434149231E197 +630CEB24061CF7BBA8FA4295DDCCAE6685FE869FB10998005268C7A35902BC6E +89A40936A7054C38446BE0172055CCE7A0C3817AA070288809EF40919236F26A +3A606A14F1B079647935A3B459166436ED4342118FEF4FAD8318DFDEE22A2E3A +930D69FCF953431FBEC18CBC1328DD7B0CFEC72C5A4594F38EBDB43B86B97DB1 +056625DB04E9FE49B79031A7E2D0702E3FDB458274EF7EC3B868FB5382998224 +4CBDA54CE2F2D68CE0381C50BB31FD871C8B3104EAF67E3550A4FC4A54789B77 +FC7F4D29A447456516EE75FE871A43445E6D47E1FB99F4BB838CD37F69EC6DEB +B39FBD458556A1D1CE56B5166F0A5BCE6581C3836185ABC5C8D4E8944B47D52E +EDD6A0A8055AEDFEF129A3F276152DEDD63C26CE00F68F3EFA16231EF33E8B22 +B35391E8612AB035F6E97C0E376AD81242C3E6ED5D2B5254F109A281CDC798B1 +0D61F3C877FBE9A4C8CED3EAAE461094AEDC3C6D81EFA599FA7F860FEEAC1464 +5307041576ED8DFDD09006924DF4E643E8923092BC7B5AC0F37DE03C882BE95F +60AD328BF44181C9C44B32F960EEFB8704EE3AA6E00ACEBD641D20C35ABE3BDE +961B752AE234EFDF35B34C313BF01B2DCE32B890DA1A811EF64A3E4F1337AA2A +622D2D242447160B1D761918E2A19006CDE5F6D7E7BE383B8D33AF5F4BB4AD7B +815BB472CA170237D1EA6330558AF4F0F4CBEF6C7D4A3AD68932E169D98C9B35 +151F9DD5A09DB1CB5185EC69A330B97B95B2EA027C5D250112207127CD9678AC +4D9460AFA630A20C8E3CD0E155AB690ECECC8D6265FB4842C7C244EDDA8E592D +C22CAB1BE287E4A390CFAE9DB02A7B877708FD9F3AEC76E4161E12864FFF8CEE +87228B5F7CE98D1E3CB77F68E3E37733A8D01EE3CDE1721F564B412494BCF021 +F2D9D8CE81E51BEFC9FD3C5B4C94FC27357AB1FB51A388406003A6EF975C0C01 +9767CE1B316830BF07496CE2FA100CB2DB417FE471CC29114EBF3B5B7FFECE8A +6FA000B38866D128C46FE3186FCAC5DDC837E65503C326BF7AB96B712DC289F7 +D6A670801D01D350A280296458DF268513E06A31E7B155A7529547302D194EC3 +E29D9E3A0CA5A1395C514E15564C1B9E5A1F80D005D6AAC30D7839DEFFE6E1A4 +0567D9C85EEA0E47016E97FCFE1F21AD2C32A5D87EF3B7D8AA763214CD42DF94 +0E0B552A6D5F3D7D7BC83E1C63C525931CDBEC2A373F02346373C673A7E464AA +82E648E75A7590A8DC398ECC6FA238238B2140D06EE227930E77B63D783F4691 +578C48C9C64B68937AEACD175F6FE505E74DE11C28F040BAEAC6167E115C12F1 +F62CCC8AFED705606D8F3584F8C100E84F7956DDD10A2E825FB7093B0AB53B5E +96F9FF9F49B0EAABCA8F85D686B15B939E487F756E6F46807EAC75A0023C886B +1C281E8DF070302BF5F49F165F0A8613400043CE8B0FCCDC83E5440873F3F775 +F84A1B6D5F53DB87F84832CFABCAEBD33D6F9CA6756B8F56E5BEE0C1F913E6A9 +6EB98C00FD70C65AB1189DE34F06071434F83F9C15C5C0F629807B29C36F03BB +8FD47F0B29A40DFE87B52ED24BC875CA6A038102EDAED255529D7FDFB50B22DE +B7C71347FB6C17FF43C71B6CC14D7F25D8F67A8877997838FEE5BC7CFC017894 +FF5A969E95370BF5C2E2523C930F5A7946CE63B89991E6C254006899FB73407C +E07CD066B320AD7E9390CB44A75732DB4507184C6FD216F4FED2B469645D71F9 +F8D310DC4D70AF3D2769421AA75148BA2B77028BCECECD20F0579C8613B90B33 +CB23D86582B012A2BC8B349DE55718F2D515995A66B93E4C9F68BAECD89ECC7F +FB6E516C2E70EC2D7B65524AD62B037ED3C614ADEEF6DCA8DAD18E8E3F6D5BF5 +0993AC3BCC98B305F1E0F7FAD03AE98CE39701608E0E706FC245585756B98E9F +7F5F9EE137AB25C6883D3764AA83831136F30E64AAB04163467F2C1836EDB4D5 +7725C14DBD1EDE2DA32F1AC55C72505E6290184D3598FF67410BD4B39C02A093 +48082CB1A2776D06E4EC0F6D9C703AA4059B6F2235276898FDC5818907900C4C +B1E849A39457DA827B07E505A4F298158399281F0B533D64874D8D2D7DDC9002 +9ACC5C03BD2388171D9B54FB6CFC60A6F58717D5B5E83E02A755C81A52FF0F4B +C0C4137A8EDC8D197A1B1B504471ACDCADB79F1D535843157697204A079061FC +6490133FB731E0E2DD597D0C4E018004CF775E0CF062B3CA9538A8F60A5E6396 +7F213875EA3161F0CC9AB19B7E13E389E9A566A03C65AA55FED61161123B8DD9 +4B0B9750BE4DAEA26FB82D324063E301C1800B3F08CE96F07290B818C5006851 +DCE19CB3CF7ED0E6E9B2EFDC2750880C578FFF977457FF8F98901E84FC3136EB +854BE53FF8E19C47E64EF87F45D86E4AFDAF2941496DD9720D6F334B759ED5D4 +EE49E7947D287118040B7F7228D6610D674474C4E4BDA5B10FEB8FA9392AAD37 +8FCC373158184E0CB3814CD91B93DEB14DAED0FBFD0D38061737A3B5F74ABD08 +C3FB0D4BD1BF7DCC4DD76428E2E0010C80983E0AC9F15E1A44C4AF49FCC44FF1 +1BE9844FDEB3E1DEBB012C6EC9EC2EA62AF434A98814C88AF04FDF703DB2A350 +46FB2EBA5CB44B0B298F18FBC50A77CD6D63A514EEF2A29C9E9CDC6CC3A5D533 +D6305E4886B710D78F2F2A2EF68EA6252E7235BBC0B499D684F9E1ABA28F9B8C +61A8B0996481C7853AA2EFFE6065DD288A0F4326C9177F718BF52CBDC601D8B2 +8F29CCED61CE524C311F5536A72E996C76DB9150B55FA6C717F8DEE1C3735C50 +6F881D7D91345D497467E77804E3CCFEF6A927AC925CA0847647E68A5BA8D056 +512B56ECBA6256D736582665AFBD22BCFEDF44785D989429CD2D46F2A4966A2D +0739BBA782053A0A0D6C234B4CBDC18D610E061812D5EAE87735BF7F08CA6A49 +CBE1E5065ACAA55A3DCBD9B9729E55B5CA96B864F5AD718DB6F2AE405F43C6B9 +BA570DFEAE69109E9F487C9B33A7A9DC2420229F6919EB461F622749A39FE971 +CA4BF8CDDFFC5EBA03F9D8B0A4872C8C35B21CD5D9C250167C82B5715D4D3A02 +3E473DF48E1C19E55CEEB97C49DBF2E084CFCCF130236B42F0EB10E5235EF00B +4E3FDCD3655A710F27326F7F6D0FCB440CB1D44FC621871C350F9E38D31EFB49 +2032271C1D99DE190B0D0E262D8C02E93449F5726DA9D8BF2EB14DA3E41CEAB9 +8402D14D60864416397B57BE2528AECAF4458E33EA016064C56816740179E514 +43810A6EBAF32854B30D184FEB3E364EE24B040E5FF9ED88DBD489BFDBCFA144 +C12C57D461DE7C5CC3ACC91B4C3E5D0AC512336C03361FB00F36F0E811EFFAC2 +447D6905E927EC8C51A6B9F508702BE34BB38BE818F4CBF1CEC2D8FDE053B31F +A0E573414A2855362ABFA3B5D16A6EACD7BE01D8143E645C37BFCF6F0404D569 +116B8E6469D7A2FCAFA8469267E9C3788BC002E07C4C314FB92514D791C8D445 +805427E60F3FD027B6B82EFB4CE3DE73378141B0A74F5ADC8FE1BF6842EF2DB3 +D59490C6DDD2CF825696971BDBB10CEA02DB63C53EFDCB49D713C6D6702B5A5C +C6B5F60B938B14B509C1EE7B32982BCAAC30E3F8D89E86CFDD0CCB9BD9CA35D0 +3722E1D135E540942BE585104591FAAFC074740C3324FDF478E88386D7A6BB73 +633A5F145AAD9C6AA0DB75303830CF8CEA51952EFEF34D11B0A1FA8ACCD1BD59 +3BC32B72139ECDFF51EEBE28E00AFBD90DB90F5721EA8915725D554AF0A014E5 +512EC137086A9900BD7509C9B27D76BB3F2FE7B66AE2A03537FCC932B5B221B8 +3FD01FF4EA87315E2B6EA4059AD6A7E525298DBEA4C2DFB36F7897A688A5D21A +17D1136E759AD00425FB21D68213FA197FE325649D67C2D83AAD5FC2B24F2935 +8F4374574E76245D873A5ED05D6ED7B65F5FA9FF7FBE9C83603A263018D87FB8 +FD61B064632C4E61557633A67D5C7C37463E13A5817E76524D169A58DB9CF325 +05AB14E05C2819C0577EF13FAAB5737BC418C9F2B946A14464162346A982C125 +B46B6DD3F89DA5289E72E27FEF3E5F5C8BFE5DA84AFCDE1B4B3138837110FAA9 +80D613C871C3B2EAFE4246DC1CB2F543836C5EB30002D39A393DF22C9201285B +2D6A02D20BA3801F4CC7CD99CCF356D95956CAFF9F72EA9B37AF87332133317F +833E4C8AEBFE403586AB2FD7E09B6385AEBEDAACBF738EB3C42A86AE20347F37 +DF04AF34B1074ADE3B81941A12C520E5EC42D775C7936B6E459E5B187D8282B6 +76DDA4B18ED89B9E98507CA86E385C6682D1F58FCE0F416FC7E396A3A68BF8C7 +1D9828FB2E9BDF2BC75B77EA3B851A32F78DAE822B3C0EDA0C29C41B4113CA22 +D17D33E3629C0D27E45185A0D922D3D4010D2FA25A425E3281ECE836BB0E9A7C +AA922A37EF2F710CC6A127568F4EBAFF31EA79C6478554E580A2D11F1ACDFE73 +CBD4C4376B4D2B1483A6FAC2970ACC2B91F38AA06BEF2274D8DCDC7E1002490F +FCDB981491917EBE4DE74329B551E6B396B63160F6476FCAB5915F31F6C5B8A8 +9137A8D98AB025179C423A2E259E844632AE44295039BCA809B1EC15221843CC +CBE82C31E9C2B8276A1507C6ADCAB40055716270F0062DC4B5957804DA8531DB +BC396FA5322412F0ACAD812068078454D3789EB3BC930A1CCA3DD08C8D4CBD4F +BF6D47846524608D21CFA4E52D0E147950BAD05FDC8432EFF01F5EF703F3C0A1 +90776A942EA49CC4096B9875CCDEFF4EB4049A1E7F2EA5D44F23C00F7A44DD3C +001378EA1FCDBECCB58259DC08D688FD64E31C27E5D9034BD334779BC0A90234 +92BAAE62A3A89B9026F15DF984BF1B79A12A7C569B4513A26B74F8F4FCCF2A23 +E9F786610BFE9CDCE0BB37BD902B56950E3F7ECD983BF397BCA5C32FE333223C +58B128C005DC5ED3934ED782C177CEB711D2287FD6C9C42C3D7A099FFD04F5E1 +52B704 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark +%%EndFont +%%BeginFont: CMTT10 +%!PS-AdobeFont-1.1: CMTT10 1.00B +%%CreationDate: 1992 Apr 26 10:42:42 +% Copyright (C) 1997 American Mathematical Society. All Rights Reserved. +11 dict begin +/FontInfo 7 dict dup begin +/version (1.00B) readonly def +/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def +/FullName (CMTT10) readonly def +/FamilyName (Computer Modern) readonly def +/Weight (Medium) readonly def +/ItalicAngle 0 def +/isFixedPitch true def +end readonly def +/FontName /CMTT10 def +/PaintType 0 def +/FontType 1 def +/FontMatrix [0.001 0 0 0.001 0 0] readonly def +/Encoding 256 array +0 1 255 {1 index exch /.notdef put} for +dup 46 /period put +dup 47 /slash put +dup 48 /zero put +dup 49 /one put +dup 51 /three put +dup 97 /a put +dup 98 /b put +dup 99 /c put +dup 100 /d put +dup 101 /e put +dup 103 /g put +dup 105 /i put +dup 107 /k put +dup 108 /l put +dup 109 /m put +dup 111 /o put +dup 112 /p put +dup 113 /q put +dup 114 /r put +dup 115 /s put +dup 116 /t put +dup 117 /u put +dup 118 /v put +dup 121 /y put +readonly def +/FontBBox{-4 -235 731 800}readonly def +currentdict end +currentfile eexec +D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891 +016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171 +9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F +D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758 +469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8 +2BDBF16FBC7512FAA308A093FE5F00F963068B8232429ED8B7CF6A3D879A2D19 +38DD5C4467F9DD8C5D1A2000B3A6BF2F25629BAEC199AE8BD4BA6ED9BBF7DABF +D0E153BAB1C17900D4FCE209622ACD19E7C74C2807D0397357ED07AB460D5204 +EB3A45B7AC4D106B7303AD8348853032A745F417943F9B4FED652B835AA49727 +A8B4117AFF1D4BCE831EB510B6851796D0BE6982B76620CB3CE0C22CACDD4593 +F244C14EEC0E5A7C4AC42392F81C01BC4257FE12AF33F4BFEA9108FF11CF9714 +4DD6EC70A2C4C1E4F328A1EB25E43525FB1E16C07E28CC359DF61F426B7D41EA +6A0C84DD63275395A503AAE908E1C82D389FD12A21E86999799E7F24A994472E +A10EAE77096709BE0D11AAD24A30D96E15A51D720AFB3B10D2E0AC8DC1A1204B +E8725E00D7E3A96F9978BC19377034D93D080C4391E579C34FF9FC2379CB119F +1E5BBEA91AE20F343C6420BE1E2BD0636B04FCCC0BEE0DC2D56D66F06DB22438 +452822CBEAF03EE9EAA8398F276EC0D92A7FB978C17805DB2F4A7DFBA56FD6AF +8670EB364F01DE8FCAFBAF657D68C3A03112915736CEABAA8BA5C0AC25288369 +5D49BD891FABEFE8699A0AE3ED85B48ACB22229E15623399C93DE7D935734ADA +DA7A1462C111D44AD53EA35B57E5D0B5FC0B481820E43222DB8EFCD5D30E15F9 +BA304FA879392EE0BCC0E1A61E74B3A1FC3A3D170218D7244580C7AA0DC65D19 +741FA5FE6F8CBF60250ACC27454BBF0897CA4B909C83A56672958752ED4B5E79 +E18660764F155E86F09EFA9F7685F2F5027EC85A775287B30E2069DE4E4D5712 +E7D033481A53A2702BA7542C71062173039030CF28D8B9C63B5596A9B42B33E7 +D922944A38713383D3648A4AF160A3B0C8F3379BA4372BE2E7EA49AABA75AEEE +C5DDE1D8BF68483C3D21271280ABB91D54CC819680322EAB72E1250A760BC8DC +FF798F2ABFC4F3539392985C4CB324B00072295FC160818BB0355FDC4F12E39B +984826450553E3D271F03D8DC2D12A92A4D32034FD16DA13B876DF448467B625 +2BA3AEEEC60550844F5300D7FDCBE636D5951411C6F46CF31F03D3517A96309E +02D0DDC6DFB8FFBAAE1AB34DAAFD32AA716301301AF68F407CFAC4FF8CAF758C +C62A6765AB1CD0F3EDD3C556A10E94426AEF2D5B015C5196CE77FA94318AC24F +D38FC825E8B2EFB8E2803754084084CF308B047CD43A736A72A30B92E1D6E1AE +BF4510C724AB326DD8B68C7B7DB16730051EDAFC10D2A983B5A2CE0505CD251F +E4B70FD350F75749950CD2F08701DED9BE9D6B06CF91BBD050A90079CA5DBECD +860FB92423ED0D24E60CE6D68DBD92BAB91FD4037117237F22BC030569DD7C79 +37C75CCC592F27B2B3D2CEAF2F0769DC82008E6D9F7E290C92BC10481409D1DD +8F2063EAF595B35F19B964E824CBCCE67DC66158348600AC510E7F30DE6D2781 +052AE66E5867DF3636C4F5C22250225BDFD3B89455E4ED9C46B241E6C9F5C635 +81EB4508FA80382BB91FDED03C2B966920A3764B754ECDC9238EB07CAAD29591 +559E5FB21A90DE77A6D1E42662BFDB8AF468B380EFA3807EADD0305BBF875D70 +87C2D6146FDE82B9FABCA9A986683FF9CB2E1937937AFA1B58AC92D62648244C +1B9AB63C41D6B7D3F6E707A89C9FE74B1C4444D059D70D9AAE0959BE049D2276 +2EE335051B39B658BB0BD12DFC322AA7F265ED2D5BD45A93A198B5AB6BDE34A6 +0974D8A02E3CC04D07147DAE41F663C6AA84626DD9470582E82C117BC35CE294 +8F7714047C77564EF036E91DB262963B00A87EC1DD570E0ACDF45494A172062A +EE8342A39331E3B5AB44B19509D77E319498517FB3E40E2B18A116878F50F7F2 +141D64C4AF7468EB5A3E0C2E638247855460167B9068FDE724EBD1572542E086 +6388A23B95F02FA1F51FD3134B1A5BB39EF20F8B5307E881A66EA939D57E40B5 +AC68571A62BB4F037146B48189FFC12ADE46DF242351C62FC7E04FF0FBE1C810 +FEBFD22BF70F556E136A227D9876F84D072F6F08F76F7B9C230CF9D843E510CE +75B2C6E45EE5623654891F6EFE237714256AEABA8B042D874E9E3AD42191C13B +8375D2ADB6037A3872340BA5F937BE74F535B57EADC58706D2218D3AA4D234B5 +BF459FFA1CD806A1647F4A2F3B5630575F64877B8367914CBEFF6BFACE449879 +AFC8349F56DDF2078C9457DF12CC19E4BC8F550B609E1FDE8A6FEE2585D01DDF +FF1F5BDFCDC27B0D9042FFC02E8F1905B65AA106C45760BC34184C1324AAFCDD +6BB874553DACBFF970CBDA0BD37AAF1B50C6F031AA9A6E297AFE238B9CE4EC6D +1981E846B631AFB1B732DA6D9177F6C37070F27A8428F256E2E1AEDEE3F6CB34 +12E4E33501E6D83008A6A366FA939A157ABA070953F605A1B5A5B6983CD58B74 +9EFDA0EA6D6275C77E42EF365E4B32E1C0CA49EB81AEFCCB0941CA5D3A4A3168 +6A8AD651989BFCDC6D7B1667D7275BD595D0FC41F5AE16DAEA552F3F17832AD3 +9C7E879195B5862CB6CD121DEB792856CA96AA9EA11B9570B6989DF44BBA1A0E +37FBB1765D20382433D46C0293E5A52906D602F8F3C0F4A4B8CE0282E3AB25B3 +02EC67ECD502611113E08638F982F095977BA363990FD17A3A58134E79E338DD +F79AFFF5E720D63E25F99825583559B6A6FE69B7B3C2932D7E026C4EF648DAA2 +19A7A89F6B370A257694CDCAD0DE05920BD521EF2C6335B4BBE32EA8D768E115 +2F631C12A2212CF31060C945ACEBD460C5465D33F1FBBF89AE0DC39D3EA407B4 +02E51F4E3714FE2BDB390A4006879AB370669701B4C81E9783EE296DB1911002 +1FA8B3E2312C472FDCF41D0AC827F15526EC91B8C357BA663A33487A53E235DF +967F366936879103F2A642016DB43BCC045D9A24C3A40009EA801A9C44E8634B +C98040E9F7AA465825AEA42F8B67F47A236F6C46A20DA5F342F1797119CD8D4E +CD92A64C54E1D1D8A88B3BD43B03D84EE751B9C408370263D6EF7C392165F9BB +C0AFE915ACD5D2BBACFA03CAD5D21A1BA4E6A220D295A263A8D70610A5A0DE99 +02D63964221A85BE09918A6A4B83A0C9C707558192CEE5A8DB04628F506C03CC +2C3394A7214C8043C1FDE4EC1BB23A974FA4C547E4911BAFE68792A76D45F26C +E940CD76993932A7CF6CD245571F8C1FE8E52ED16AEB006B104245AC011E421D +B3E480FBB806C76A0832F2CB44086C736077D14E99B5E36009B5B438F53C8861 +0634656E49B1C7C3C9AF1BABED78506EF07B2EE65103C82F7F91B37F0C687642 +93AE306EFE2B233B9F0FE5E20FC5781C56655D060E34EFAAB4A39EBA9917D13D +FA7A8C196BA4B6E8B1CFCB56D215BD88EE9DD795696D4490D483732B92CDB1D4 +4069C2FF53F9E548A8F329B3670726A98F3F631731EB6B2AB685190AE4FF0618 +6763C5D890CD5BB611E24AE8E5BDE30999E37D2AED81D193E41621E69D862F27 +92F072C6792492363A02DC88AF0A3DAA142AAE47B4C17B0B2FC45DF2AF393E7A +F96CC968AD097DEF82B3EAE17DB2EFD5173B0836DAC315A525C9741DF3EE3DCC +8354BA35DBE9F05D490AF7708F69873BE003679D1B183955617276883030F271 +ECF4448879942BF2CB4E9A46B0D996AE6DBEF3CCC8901CE222CFFB509134229A +1C45861DC64333A6DF19CFB35A9C81CA43F292B7ACBEF028F73E0674A748DA46 +3402590D9615B502899CDEA02D4D781CF293238175097CF710C42524F2458CEF +1675174539291F8C16AF08FF339F4E007EC9B5960B362CF02E299A04B215D677 +AAA0CB7355CB26A82F29387BD4688CFAC7D8EDDCC4CCACC2D3300150766CF57A +D9E631E76E37B66B24CD9A9F5B34E5E798BF7DAEFFA985930F938FE7A749247C +280961211A12FA83AD620FFFE317F111A298DD8027B45FC937035FE917CC5BB7 +976C0FE5E4EDD10AE838BA74E926E35C2F72BC759F34BCCB5FCDC254D14A88F3 +57A1098713177EB7D25E98F0B43CA792812B5280365B17CF98854F312344391C +52B5B9FFF2B937925759DC183C69D2685D1688B50EA69AF7E6AD8994DE0838C6 +CA7938B336C2A576BF07339A7259FD3BFC4E3185C5E17F27F5D6406639961717 +DF883E01B6B18B764C1EE150B9176C3074976FE446CE98AA8EF1F5DCD77DC561 +D65BA4693AEC307E2ED5B22E604589F194EF35582C7141C7BC583711DE66862B +41CE5CE458A940280B14C60ECC1E522869824D8E67DF2101E4B4E55618C52219 +6F2CF1F018FAD677E5295B180068A9F89D55B5B7597CDD6A57716AB45FA70A6E +8EC6D2924353E639F75D8EEFD8ACFB390F42F50361F2E03DA648AE0CF255F0DE +48DC5A539A5189C5A596C29A0B05AE8624F3361370DC17AD30024635F6757694 +BF920BDA58DBE1C1ED06BA61119B564A57DAD212019ED36F97554547E50278C2 +4D16D1537DFEC8DB97C4EACB1FF3F244AEEEC016E07FF3BDE5F1220D90C7E8B4 +0A151A130528E551FE31E3ECC9B6C3CB78C26A8D2611FF071E2C4B90662434F6 +4BF4F10ADC87CC5A61E61B9F6F630C5682B09DD6251FA40C9B09A4C2F7B48FD9 +4228961EE52CA9F7ECC7E6034BCA172EF44BAD843530CA1B3F7AE17BC6AB4B58 +16A3C87E8839B0C3A6935E6475B9B03FEC51E012A780094A82CEE377C8F24CF0 +97B7EEBA0F341918253160887CA4758E3F32CA58FAC27A27B5B661149B93AD88 +2C7047E67605B95C00E39CC270CF8406D1BAE3E1AACC9A48F839D89BF0AA31BA +D559892AF03CD3F5C3B25FEB5AC97E637CF56E00731599ABAE5FE0692CCFA46F +03F1DA110916CE7333BAFA1543EC4A1EF6F497EA5BADF79DAE6B05770F398A21 +5DD6FADD305DE9C1E1D129BF7ACB3E158A4C6B7BB647E3DA791A2F3AF4453E9E +7201AF72B3E69DA1E5718E56CBCA82F8D7ABE1B2C4E47607E160D03EEF957659 +11098030C4D8FB4B8B054F33DF237A678EA8D555571B4746B823637D64B43EEA +C4C57B40B81C3068587DC666A6A78AB696B58A37027183C22CF0491EF2910DAC +064A959A94F510B0C154283762E194FD7ACA1C15CF9624EAB2790A70F5206E4D +5F5F0715E7DA8D7D37C4A9F6122D8D73DDB2BD6AD51D6611D38548F4D23F8A75 +98A5113CF81A228F90D613D416D6BDAF67C2CD792C5E6CEA9A975EFA0E643CB3 +D54BA56ACBE0B558D816E0FD45B422F651688AEC32AD63D18CE9A24061B27744 +E2A9DCD6D9F6CB4A67B93778C80535E51C0E12533FBAC4392B0B04D5F448C511 +6DA6E0C513CC4019550F9ED46612BA51B068E1E3345251B37BE71B7D76BAADF9 +1E0FD6158E7241D8231800CA4258EB0ACBCE7CF6EA276634CEABC8A72A34BD15 +FFECF5795F0BF342D00A3070DB2DEE66E7185B707C52463B8A6602202BD2E845 +2343F15913A1C444553723C57C3C6BFC4C5BF3EE324806289DE33908F811827F +54346E441E51E0B1DB2E3EC2705F5005640187863F38908570EB9BA819F02494 +F1EB39795300F6F806AC50FD3E027A18B5ADDEE0415F17979E8BA9B2EC293182 +127E43C6DC0EB839749D195C4F5B87A7D0BF22DB663190CAA40FCA8474AED7BF +73CBBF240A0082FE3BCEF2D7C659AC3E27591C59E433592A8440C6EF987D0BE6 +057B3ABA379CE1ACC80A526FE4F85DAFCCA8EE55EBDF0BD512D319A8E8335DE9 +BA2A4BDE294E4033547605C3E0D43A89C7CF9BE09391ACC16891F472E72A31D7 +D405A7A506AE94251A9C7D36B0704B876160CF332F18BB51A1D9B0C5995F5E13 +EA4CA6C0D07B4D39A23DE03A10965429E58F7A99E883D778A776777D86F4B6F6 +0DF21CEE265091D3297A70BAA796DA12F91A5CCC7851F1038A43B3D726D85B00 +F0ABE7A655F66F53A01A34F6E2FF11F1AEA9C35EF212B69389D0273EE546F6BC +79A0C53701212FF5669ACF2DC8693B2544C52530F29E319B39FBDB73C759B3C2 +DADEEA42048F48CF5508E7694FFD62B423C0D3A0DECBB87E27666A8DC9650ABD +9C53C3121160962D5FBE94C7495992BEC729A00B47E27A9A17C4826516724D11 +438ACDD5BF5C2B2104FAB5279058CF43278F4F2D572A200FBC20A338F2FF0EBD +12B9D8E87D699F679BDBA6CF30121DFA188042FF84D720DCF711A8F198B7CD57 +C2D79989A9A208A1583EB72E93499AEC46661A75F38C9A603B6CCEB3BBD28A6C +C7CACB5E74292F1BAF7BC7C8C3C6CA23FF02D7C9C3A6818F9A26748AE1AB4451 +D78E328353610ED344ECC5E1553FFC00A95DD397347839CA3421CD7C63560B8E +38DA27AD84A1135ED4B9F54CB94BF8FEE834A5C1A4C2E023B831AE5067E136E2 +E3F22594210540EDBA97E15C457691E7862FE68AAE12533D711457BEE18D2366 +BC58301669F343DDAD8807B20F2BC3884766422EEA2BAD08CB0DD5DD927E802A +08C93ACC21AB251746EC88366B149E97DCBFE9B7291656DE495AF1F2031B260F +CBAAFC0D3BE835EF99AC2C546E8D4C7137E91EBAF8B2898A77C27C61D4D6198A +2650550CB4B55B882282E1453C29CC98EC408F5F58D8DA0955866166CE62F33F +4D1514D55407AD1E341F6D74F9CACF511EE7DC35E9AE732C7863BEB3E0F2F162 +54306B39095EDE63C24493985B8661A878F6E4406AE96F7518219BC0D0CEB8CF +EF2E9EF481C5964680EE1032D5D31815E889A4CE197F192701BEA3F4894459FF +D6082B7E3AA12778F49456F505E39496B54EB85FB6364006AEB9969B97359769 +581E03BC89EAD1A44ED1EDD7CD602B8967F3F9F501F3444C2829F2038AAFDC57 +C825D41C01D32D28A8EBB7B31B625EA0BB332F20EE567F6185657A5911590EA0 +9F9A21E90AC4831833BAB7E86DF8B6EE16D549464399A630CFF115678BC6C6A8 +0567E70FB756EC185986F302714892F64FFEB34B69F2E3243ADD9F4F3DDF9230 +D261A79B239BDCF8A5A64B4EFEC55F3D78EA1A84F114FE87B4F753B6B3535938 +81 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark +%%EndFont +%%BeginFont: CMSS10 +%!PS-AdobeFont-1.1: CMSS10 1.0 +%%CreationDate: 1991 Aug 20 17:33:34 +% Copyright (C) 1997 American Mathematical Society. All Rights Reserved. +11 dict begin +/FontInfo 7 dict dup begin +/version (1.0) readonly def +/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def +/FullName (CMSS10) readonly def +/FamilyName (Computer Modern) readonly def +/Weight (Medium) readonly def +/ItalicAngle 0 def +/isFixedPitch false def +end readonly def +/FontName /CMSS10 def +/PaintType 0 def +/FontType 1 def +/FontMatrix [0.001 0 0 0.001 0 0] readonly def +/Encoding 256 array +0 1 255 {1 index exch /.notdef put} for +dup 12 /fi put +dup 40 /parenleft put +dup 41 /parenright put +dup 44 /comma put +dup 46 /period put +dup 50 /two put +dup 52 /four put +dup 61 /equal put +dup 71 /G put +dup 76 /L put +dup 79 /O put +dup 84 /T put +dup 85 /U put +dup 97 /a put +dup 98 /b put +dup 99 /c put +dup 100 /d put +dup 101 /e put +dup 102 /f put +dup 103 /g put +dup 104 /h put +dup 105 /i put +dup 107 /k put +dup 108 /l put +dup 109 /m put +dup 110 /n put +dup 111 /o put +dup 112 /p put +dup 114 /r put +dup 115 /s put +dup 116 /t put +dup 117 /u put +dup 120 /x put +dup 121 /y put +readonly def +/FontBBox{-61 -250 999 759}readonly def +currentdict end +currentfile eexec +D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891 +016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171 +9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F +D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758 +469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8 +2BDBF16FBC7512FAA308A093FE5CF7158F1163BDCEEA888D07B439DBD4E8B4C9 +D198C03874B5E6F8FBF4922065A92BC3E66D05DE53971CB1424510E892442858 +D69CE1F76E4DA76C87C763A4B2FE36321E54B1328C9155B8ED6361855A151723 +3386AEA3D042B8D89C8C0E9A33E5DF3B466F7BB8C2C8A4ED4CDAFF55FC6D3EE6 +0AF2CEBFC1AC3A6E6692F8BB81F82D86BAE85016AD62FCB05467082C2E5AD348 +44D1439C2B59F65590E57CA0DE481A7A34E79931B1513C4C30156170409A4BB8 +46D412D1DAF88AD30722F12DBCA1CCC6B4BCC28D06B0D29149DDEC520C8FBA13 +6B82E2E1790F00B216282FF122EF0D47B70A1B29514DDF7C0435ED238C14BDF5 +6DA243117FBEF7398F97EB95597707ED63C6797EBA1B46EA19ABB1DABDA171B3 +16CD500F5D64CBFBE4F9CBC3E66A34427D3C4D0C432710289381F9BFD91B4FF4 +1E3A896C3EEA2F3105C218877D6C0C6B763760FA364D00065E1CAE9DCB5676ED +286A9ED0D1C946DCA6A2A670EE0936FB4706CC62E234CFEED34AA615C48D2872 +A087F30990C85E64BA68F3D5C117123467DB411C9F2D6F6858CC70C1E352C477 +713097321B4C4FD4C5CDE305415F998E7245908EEDE6E056A736EA77BD8C639C +3A79FFD0B74B3D28F0494A115F2841CF8A8827AB5608F96FD8998A5F40FB3DFE +3AA0C7696DE4E1D18DC0D6E84B943175FC38FFC42A9C0CBB13A908978C98BFE5 +034F88480F32B9DEB2FD228FF6CB0B89B045AB02020C82E3F5716DC640613185 +9F597CE262729BC52132F43922B9E28BB71A30AC8709634561B22D13C4FAFE0A +12C4451969226B220038AD8DDA990A4E2CAD53DBEAB698898BBD3046234EB4EA +901287E71CB41296C431383AB85F18882F65BE36923F6C0FD6FADAD08E203981 +91143E0EF9FDB372272A29A1AB5CD93D06357312C5B22D1429B25CA37ED5C4ED +6DED836928CA720EF466398095918C1C628876B98A35ECC3CB00AED9E939566B +D2D979B965A5C1AD47C68947273EAFEDCE538901C4155C7D112B5AD4939C0813 +C6FA7D0C841F35278A8D4BE1408A3DC0A8AC604B6761CDD563554AEC1E0ADE56 +5137BF4297C87F1A79A9E6B81674DCEE3C0FDE403E4CA14145B5B341559D16FC +E9B547D91237B737EB0268BA1428943D0067E7FD7B7E994118DF1A39ED5BA3F0 +27E2CF8C70E6E437842CFA59EDC921A744637843F4993A0ED6E399F22DAB798F +EC1B89BAFE9D3DC8B5380BB4A4B3439921996A6EB049F858E44B3CC9AE8431CE +E5255538A0E3C211A8FF625F66D9B8C2127AEA2EC8A556C9A32016E1B8626847 +6A689F4EEFE3449A9FF7F584DBBA2A62F22C4177FDE1531C0BC9FD0C83D113DD +54BCC1585EE89C8D426DB3E48057E39774575871631AD1082CFDA31032A6813C +D948B260E0582F39D248B172F609DDBBB69CC40B5CD8B3D127BD99A539B52347 +FE0A4791C8278DADA8D43AE4FDA9BFB6CAFC37E848D666A188AE291FE3ED09DB +735DCDB656D6BB72D0837D5C612B44DA7CE779DA6F96B36C461D527FDADB79D1 +F2A2ADD34DDCAB83126C69F1547A588C8FF5250BDE4D02B72BFD3C106B8006CF +96B0312F65010428F866B947EC79AC79184467F426D6603C80B46BA8EDD8932B +03AEF0497C14F751D4730AAABA7FDBC329642013B6B6AC3BDD19031BB5EEDC5F +CF41564C50A1DA21879CB849E4B929DF99B84DFE590E9755AB90581AD79BEED0 +69389990A120DEA5A12E25907305F4FA1468D3F131D299EA305F9BCE0A81E05E +C9A0099A46ADF6F3BCE3C0C72B9D7E83D5FC5364068BCA430B4D0E599FA941D5 +32A647D2037FEC35A3193A16DA038D63C40881C6916DD6F7FC0B8569893D3D6F +AD0F461D13C5A43055FCCC1079C5D0AD3FACC5B6A9F74C2F6EB9EDC12FF2BFB0 +6CC9DF55E045AE298E03C0AD3D403EDBDF1557592606F07FCA5C05936DBA400D +83D45D56152F95572A890DB93D04F0AF62D2888721F0DAC5A79C86A7B8C9DB66 +F3C8F8090D43C7E17DCB31E3D03430CD8C010584B322D89EA69EA8EA95A5FA17 +3B2F166FA8F3F5AC3D19039390E271C809FF350C737FA62837EB395AF54463DD +8B2D9917347A436DD20CD78A0765E76B99CB422441356C4B2F8DBA7FDCCCEE4E +6313A1B451E94605EDFEEEDACCEF1699487FD102659990472019FA352792E441 +6D792157D19F87BB59A2D03EDE7041F019C67071845B51B02996DF9933261D5F +D17E3EB088A9B5587D9CF0D6E0F701CA552DC2B80A51A86A59334BD1AEF39637 +B0ECDAD2D441632DF7404E8DB7EF9AB0EEF2A38BE850FD5E96F97600F3819E4A +08F4BA59200BE755055DF84FF7E23789F7880B91BB6FD046FEF467F56AF8CF8A +DAAD98822F73ABF97521A2C1CAF87579033A3DEEE8E936E7C9B066C8D86F0FB4 +AA0A3F4522AE0C87FAB7B0EDF79BA0E920AB2E07111D0DDA88C20BCE54A75571 +EB92965857A3FB2B1A8970250F7AC841F9A169B01AE2BA30D11B78CA3925E9A2 +CD453AEB31FA3D6495A98CEAFC5D98A813C2467771BEB55C153E5391DEF30154 +8CB364D0D42578F27CE4DB0A82F31360BE5A66159B20448F4DB13BB630F3EE52 +2D03B87C67CC8BAC0C85D7234A89ED437F574451D01E0876679B746DD23608A4 +A5CB6750294C2BB67BA8814F93D5EDC13B3C79A7112DBC6877E13F012183C0C5 +AE1474919E2C09034450514DC3C98D6D1B03093E3CD318768713D82C88EE559E +4EB9092A63D9A8575AB7FE3A59F74E09124CDF7CDC0E243E43AC4220198A3F70 +6817AC4304B5529CE3D5567720A4E4E1896F94B33D0591808BDEC081A430CC06 +6CDE221418C30F3600661FBC6ABAB61608A4AFFC68C7069CBDFEE1F3F208437D +EB8CC23A02154E37C7033E544B675D7D56E01DA19609FB83601611A17C2550CF +CA248EBF7ADB0237BCA87047DDEB68DE39DF29A440118DC58FF9C9FC67C27E26 +67B7F8DA80ACF45F3887A2926424865424A572B4745200C1E5862B7E5A3ECA56 +2BE28DDCF307123AE11FF21D454C3F0DDEBA97990E42D9551E057AF445303873 +8F0884375C676613330D5C70EA193781C7131C81D40EAB9CDC02925B9E23A451 +AC03EE98C498BD8D9CCFB18095202FE92A1D0A98AB3EA027F283B3FD93E62534 +85EF92F6370ABE7FAC6B71053A2A770DF0315F13A9F3B49BFF60F3D2A07ECC17 +6119082BF58BBC233F3A778898DA5B09841AF2E677D2E91B3EBBCF3FE438461D +10087E3EC6365DCEE9CACFF0D70F83F13152F79CB9DD8BFA2FCFC3B7397E3C59 +AA8DB80A542C3D15468687925170EE9D39E62176C7FBED64212309DEAA6ECB29 +F4894A3E4EA963C9D3D4AADCCEC0F1E1453E9B1DC0BAE4BC9034D90E712F2435 +7ADE0BFE4B18D4D2221DB6DD52EDABB5117D733F0AB35F6FAC8E6B84BA5A3FD3 +7638DC29DBCCB6CF35F2E0600A7A3AFBBC180EF267D2B7AAFD33919FABA6E4F4 +0C6E383FC41FB6E7F743937B2C7F9F0ECE5A44418477CDCF5380745A43DCF54C +7012D14583E9DB1CF6FAF23C1F46D34F3E3477E8F548D990559AC157E78FF289 +F0A5BA9DE4B8E2C8A3FECAA94BCF5206CB66568267B501AAD1A42213A55659E0 +82D080A46BE07D5926E17A875DCB1FB4018A7514323238E1DDFE28EF6A3E0D2B +51A6C635395CA25FFECF751394E915995E6EBAB6065241D3DB40CCAE45A6AFE6 +474242B14C20497DFCEF9817F046D4A4C6E674AF6493373F69C5B96B71FBD7CB +108F13F1C213E0426B0E67B8FE593496D72954468DE2866AACD6D5A2CBFD438A +D2316C8F1124C2D5CA4554EFFF5BD0FD3244BA8F4ED21C86190317DED92A95F7 +3F7B6E3613E16E6C31AC5FBFF063B0882111E6F13DB2673D3ED519E8CD322A3F +67FBA217F062038F41C981FA3C4FA389F33B2B973532A1A24A8AACA011E29A1A +24D1AD021B756FD486B8E1D8050E991C52601FD8E8B347B4A34D17AE48DD5E95 +8F4FA1BFE9141EC0FDCA20FCFE9C93DFD366766DDDBC281AE6C34C9137AD4559 +6E89F75CF20C629C9F977C32B3C021843E7B0ED59B7C1355F4C2C276DE1131B7 +3010D2742D2EEAEE96974311610E4023F67560B92E354DBAD3BAC9F4E9768F69 +76EE1FCF959FCAD9F23D090BB5F0DFD6D84F1ABA1EC906D9F251FDACF85958B6 +FAB6E1987DD9E8D3B33014BDFCEF349A952EBBD8A5CB72B15BF31A7841CAF39E +02B75F72A2DD250FD5BF628B707BF717551B43CACB6FD8BBF9CF0FD42CF4B52F +0D2FB66A47DA2CCE9513D51715DAE4E078E74F70734494390C47CC2E8E29CD5D +26C727615DA35F7C4A9E74B9DD97A774AF2CDF3D4E47DEF1FF8B89F65D3D918A +D971248BA4186606262F65DA7FC695B188DB7EC982956AF1D52543EACB1F7637 +E2194996278F21D772524517A051C8776085254DBF6C97AEDC0B53C17B3182E0 +AEFB665924E4AD61F36FD1AF3AD0C0E3B575A634A73C89291C073376830A107D +47B61292D05CE54D40BBEAC9E1EC7E51A1A18459B9172D60CDCA7D8CC5399DD7 +BFF99EAC58A7C12D7F6FD3531ED49264BB54651B46135F83F1D838FB49C2CAC9 +1E0D43C1EE427B2A09B063E8C6C8C837B78ACD823044C569B558E629069BD679 +4D0CBF5C8E58B1BEE121223851B62F479F3FD2A99AE6EA88B9954B3592F1A38E +D831BEFA92A9B91F7BA08D0C999ACEB1B86BC0A8F90D55B80C0A14D940C1E84C +D1A0CF8F38AB79811BC5745B9ED93026190984904FB938FEC6E28633E4AB179C +5097517C1CE2AA889BA06DE9C4C465BD3465CD7DB8456DAF1B0BA7EF3CAD279F +25A171F32BF4668BD606C70660207093FF58C26E7BA32E7F4ECEE1A4177047F2 +1A1B64AF0CF1BC01C9AD73B9D6FF0C0D2C075DC5ED5CEBBA9DF43953AE510BAC +C7B120AF1426AFECF0F058143E84DB89B024202BC8E15C9B593B8AF449BE3D41 +D72A82F64F4915E3B77D0280E6F326264F6123870AD27EEAA5C1061F5C1AB7D2 +46A383ED44399CFF26124DA18FCA8C917D6C41660AD3976CC2499914BB0DE761 +9FB186CFDC29EF5B7918D8F314754750AF2BE33428C21561E883B45F6AE9FD11 +F78F949561B9D12D3707D6AC2937BA4FAB200E7677D6C47EA1554CA406047BBC +5597B2BE02590F94BE17DEA5582B7F7866D87EBA14B1AF2E6DE81F26FA6CD64E +F1EA10743CC8999EB3A43408C6F14B39F2D5A4EA291BC8857E69170480BED992 +98E8CBB19F22F89830FB626BEC68772786A3C210AF8EA524217371C88EC9E3EC +E2E4B4582C837C349BFA1452364BD4863FE4BDB7A37C31A7B57F208ADD5BE237 +19D6AEF576EFF1BCA86F0D874FDA320670B38CE306A96604D36DC98A94DB5715 +A026444DC003852CF82DCB6B1BF6DFE3A25982531BDEB5E6B941A4ECAE8BC947 +604B845258B83CE9E723069171FCB8C95CE4862B429B1AAB319FF6CEC21592E4 +733E6F778E4C8C6993DD546BDF6F84C23928EF996092E8630DDEACB3D36BCDC6 +6D7F2B45BAAE296888EB203A425409C7785AD6D565D1F3D4EAA5869FDB2CA737 +046FBBDB028A16CC4F2E00842F45E432E9319BD4A532DEEF69D54D80D6612F4D +39650882404A2C3830B9AB4C327B4B54A6ADFEBA95ED677C910F8969F227D815 +97EDC221AA142ABA4C762DD35D43454927517EF0D45EED5DEBD177316138F98B +638F3F765F54EA4E5B068BB94172B756BA24AE8ACF60C8257FAB88C5D35AE24C +4BDA455EE820F02682C069F3511AE807628F51068F80B5CF6B5378B2A6E389F2 +5201C75AC54571C6D1C69E9DA9A950D47051D6C8BDEB9108087B5D417A90CA72 +E1B82630183FC0E343BB26675BB6FAF559DA339ADC0340BD6148C5DFC3967880 +6AC4013B609B441154BD97663A5C663CED743530E90ECCF2A19371DBA1CA3626 +899F88938E1AECE40D7B866580BC07F724FA44AFAC36490E3918292815EB639D +EEEC79557F5A281DA428BAEAB9D7CA15E88A953E0CF5F3B3AD5677601BD65F86 +EF01AB99334A0B59215EB4407AD0B4E4AAFBA14AD03427E916749251EEB119AD +85274205FE66B6892B0DE83E6FED65592D777818CD7CD334B42BCA431658DE70 +6605C5C08F1D0096F021718758A1E4F181F53BD0723B41EF657EA858AC73C88A +7EBDBF9D958B9AEC90103B7DC14FFC64AE5F +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark +%%EndFont +%%BeginFont: CMMI10 +%!PS-AdobeFont-1.1: CMMI10 1.100 +%%CreationDate: 1996 Jul 23 07:53:57 +% Copyright (C) 1997 American Mathematical Society. All Rights Reserved. +11 dict begin +/FontInfo 7 dict dup begin +/version (1.100) readonly def +/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def +/FullName (CMMI10) readonly def +/FamilyName (Computer Modern) readonly def +/Weight (Medium) readonly def +/ItalicAngle -14.04 def +/isFixedPitch false def +end readonly def +/FontName /CMMI10 def +/PaintType 0 def +/FontType 1 def +/FontMatrix [0.001 0 0 0.001 0 0] readonly def +/Encoding 256 array +0 1 255 {1 index exch /.notdef put} for +dup 60 /less put +dup 62 /greater put +readonly def +/FontBBox{-32 -250 1048 750}readonly def +currentdict end +currentfile eexec +D9D66F633B846A97B686A97E45A3D0AA0529731C99A784CCBE85B4993B2EEBDE +3B12D472B7CF54651EF21185116A69AB1096ED4BAD2F646635E019B6417CC77B +532F85D811C70D1429A19A5307EF63EB5C5E02C89FC6C20F6D9D89E7D91FE470 +B72BEFDA23F5DF76BE05AF4CE93137A219ED8A04A9D7D6FDF37E6B7FCDE0D90B +986423E5960A5D9FBB4C956556E8DF90CBFAEC476FA36FD9A5C8175C9AF513FE +D919C2DDD26BDC0D99398B9F4D03D5993DFC0930297866E1CD0A319B6B1FD958 +9E394A533A081C36D456A09920001A3D2199583EB9B84B4DEE08E3D12939E321 +990CD249827D9648574955F61BAAA11263A91B6C3D47A5190165B0C25ABF6D3E +6EC187E4B05182126BB0D0323D943170B795255260F9FD25F2248D04F45DFBFB +DEF7FF8B19BFEF637B210018AE02572B389B3F76282BEB29CC301905D388C721 +59616893E774413F48DE0B408BC66DCE3FE17CB9F84D205839D58014D6A88823 +D9320AE93AF96D97A02C4D5A2BB2B8C7925C4578003959C46E3CE1A2F0EAC4BF +8B9B325E46435BDE60BC54D72BC8ACB5C0A34413AC87045DC7B84646A324B808 +6FD8E34217213E131C3B1510415CE45420688ED9C1D27890EC68BD7C1235FAF9 +1DAB3A369DD2FC3BE5CF9655C7B7EDA7361D7E05E5831B6B8E2EEC542A7B38EE +03BE4BAC6079D038ACB3C7C916279764547C2D51976BABA94BA9866D79F13909 +95AA39B0F03103A07CBDF441B8C5669F729020AF284B7FF52A29C6255FCAACF1 +74109050FBA2602E72593FBCBFC26E726EE4AEF97B7632BC4F5F353B5C67FED2 +3EA752A4A57B8F7FEFF1D7341D895F0A3A0BE1D8E3391970457A967EFF84F6D8 +47750B1145B8CC5BD96EE7AA99DDC9E06939E383BDA41175233D58AD263EBF19 +AFC0E2F840512D321166547B306C592B8A01E1FA2564B9A26DAC14256414E4C8 +42616728D918C74D13C349F4186EC7B9708B86467425A6FDB3A396562F7EE4D8 +40B43621744CF8A23A6E532649B66C2A0002DD04F8F39618E4F572819DD34837 +B5A08E643FDCA1505AF6A1FA3DDFD1FA758013CAED8ACDDBBB334D664DFF5B53 +95601766777978D01677B8D19E1B10A078432D2884BB4F7B8C3293B68BB78100 +16724E495064BA0168CC86D413CB48560D6D318357397832F7A858CD82030C7D +8A4A1919716E8B26AFF8789AAF489EE4E0A88DC477551A87C7DF2856189E4596 +FE015956AFE5CC019F5CA6323A12B763B7B08B92C1A2940D3C566C43729E5482 +63C6DC5E834AEB4DAFB5AE8F0B8931A4687C94D11587B9071C8D81DA14F12776 +53A1985A3EBE37827656BD4635E03F09C3231F906874645E7DB3E59045A59D67 +E745D8487CF73FC50F64060544F624F357BC998A87FBE468DEBB38A09449EBCA +D041D7C29225ACD16CB8A59E87924D15A9125F064710A6CCCA3AD3103D8FCC94 +CC3571C6F9192774FCFE5BB42A14B27960903144D28BF047BF4C77646EA7BF6F +440D4EDEB712C63F2E8080419E42D1D58EED685EB5CDD49F80DB6E5553B519FA +C6A39A093155802F3EC607721F390307E91ECB597ABA60A537E3F8C045BF5DD3 +D88CF6518D37FCD95D2F295D902D617440D23516D962F47750A682A319ACE1 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark +%%EndFont +%%BeginFont: CMR10 +%!PS-AdobeFont-1.1: CMR10 1.00B +%%CreationDate: 1992 Feb 19 19:54:52 +% Copyright (C) 1997 American Mathematical Society. All Rights Reserved. +11 dict begin +/FontInfo 7 dict dup begin +/version (1.00B) readonly def +/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def +/FullName (CMR10) readonly def +/FamilyName (Computer Modern) readonly def +/Weight (Medium) readonly def +/ItalicAngle 0 def +/isFixedPitch false def +end readonly def +/FontName /CMR10 def +/PaintType 0 def +/FontType 1 def +/FontMatrix [0.001 0 0 0.001 0 0] readonly def +/Encoding 256 array +0 1 255 {1 index exch /.notdef put} for +dup 11 /ff put +dup 12 /fi put +dup 13 /fl put +dup 14 /ffi put +dup 33 /exclam put +dup 34 /quotedblright put +dup 36 /dollar put +dup 39 /quoteright put +dup 40 /parenleft put +dup 41 /parenright put +dup 43 /plus put +dup 44 /comma put +dup 45 /hyphen put +dup 46 /period put +dup 47 /slash put +dup 48 /zero put +dup 49 /one put +dup 50 /two put +dup 51 /three put +dup 52 /four put +dup 53 /five put +dup 54 /six put +dup 55 /seven put +dup 56 /eight put +dup 57 /nine put +dup 58 /colon put +dup 59 /semicolon put +dup 61 /equal put +dup 64 /at put +dup 65 /A put +dup 66 /B put +dup 67 /C put +dup 68 /D put +dup 69 /E put +dup 70 /F put +dup 71 /G put +dup 72 /H put +dup 73 /I put +dup 74 /J put +dup 75 /K put +dup 76 /L put +dup 77 /M put +dup 78 /N put +dup 79 /O put +dup 80 /P put +dup 81 /Q put +dup 82 /R put +dup 83 /S put +dup 84 /T put +dup 85 /U put +dup 86 /V put +dup 87 /W put +dup 89 /Y put +dup 92 /quotedblleft put +dup 97 /a put +dup 98 /b put +dup 99 /c put +dup 100 /d put +dup 101 /e put +dup 102 /f put +dup 103 /g put +dup 104 /h put +dup 105 /i put +dup 106 /j put +dup 107 /k put +dup 108 /l put +dup 109 /m put +dup 110 /n put +dup 111 /o put +dup 112 /p put +dup 113 /q put +dup 114 /r put +dup 115 /s put +dup 116 /t put +dup 117 /u put +dup 118 /v put +dup 119 /w put +dup 120 /x put +dup 121 /y put +dup 122 /z put +dup 123 /endash put +readonly def +/FontBBox{-251 -250 1009 969}readonly def +currentdict end +currentfile eexec +D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891 +016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171 +9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F +D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758 +469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8 +2BDBF16FBC7512FAA308A093FE5CF7158F1163BC1F3352E22A1452E73FECA8A4 +87100FB1FFC4C8AF409B2067537220E605DA0852CA49839E1386AF9D7A1A455F +D1F017CE45884D76EF2CB9BC5821FD25365DDEA6E45F332B5F68A44AD8A530F0 +92A36FAC8D27F9087AFEEA2096F839A2BC4B937F24E080EF7C0F9374A18D565C +295A05210DB96A23175AC59A9BD0147A310EF49C551A417E0A22703F94FF7B75 +409A5D417DA6730A69E310FA6A4229FC7E4F620B0FC4C63C50E99E179EB51E4C +4BC45217722F1E8E40F1E1428E792EAFE05C5A50D38C52114DFCD24D54027CBF +2512DD116F0463DE4052A7AD53B641A27E81E481947884CE35661B49153FA19E +0A2A860C7B61558671303DE6AE06A80E4E450E17067676E6BBB42A9A24ACBC3E +B0CA7B7A3BFEA84FED39CCFB6D545BB2BCC49E5E16976407AB9D94556CD4F008 +24EF579B6800B6DC3AAF840B3FC6822872368E3B4274DD06CA36AF8F6346C11B +43C772CC242F3B212C4BD7018D71A1A74C9A94ED0093A5FB6557F4E0751047AF +D72098ECA301B8AE68110F983796E581F106144951DF5B750432A230FDA3B575 +5A38B5E7972AABC12306A01A99FCF8189D71B8DBF49550BAEA9CF1B97CBFC7CC +96498ECC938B1A1710B670657DE923A659DB8757147B140A48067328E7E3F9C3 +7D1888B284904301450CE0BC15EEEA00E48CCD6388F3FC3BEFD8D9C400015B65 +0F2F536D035626B1FF0A69D732C7A1836D635C30C06BED4327737029E5BA5830 +B9E88A4024C3326AD2F34F47B54739B48825AD6699F7D117EA4C4AEC4440BF6D +AA0099DEFD326235965C63647921828BF269ECC87A2B1C8CAD6C78B6E561B007 +97BE2BC7CA32B4534075F6491BE959D1F635463E71679E527F4F456F774B2AF8 +FEF3D8C63B2F8B99FE0F73BA44B3CF15A613471EA3C7A1CD783D3EB41F4ACEE5 +20759B6A4C4466E2D80EF7C7866BAD06E5DF0434D2C607FC82C9EBD4D8902EE4 +0A7617C3AEACCB7CCE00319D0677AA6DB7E0250B51908F966977BD8C8D07FDBD +F4D058444E7D7D91788DEA997CBE0545902E67194B7BA3CD0BF454FCA60B9A20 +3E6BB526D2D5B5321EE18DD2A0B15E53BCB8E3E01067B30ED2DD2CB9B06D3122 +A737435305D42DE9C6B614926BFD44DF10D14402EBEDFF0B144B1C9BD22D7379 +5262FEEAFE31C8A721C2D46AA00C10681BA9970D09F1EA4FA77428025D4059BA +2988AC2E3D7246BAAAFB89745F0E38580546045527C8779A254DB08DCC6FB9B9 +0E172209FBE3857AF495A7F2B34BC893D942C145C2204CFCD6A5C69FEFC25B60 +E412CB2BEAE7F7FAD03AF46344F6A7D483BBB1E896BF16B0F4C363799DF23CE2 +E8127996DE841B6F9D8A9E56BD799B6A938582988AF87151BB8D3AEA85C49857 +DD862B5E10D9F33D57795D656FB616BC9B8397B3612131A2B0F472656700958F +739A548F7C3A348698AF9F6F9821D7A9FD4131781ACBF7EAB885A3AC254DBF94 +02FA697941A0F97F048861788BEACC20DE829764413CA58F9D045A6B38BCD6E6 +E4827247EDF1171F64E3B041A69B244308DC07F66643FCD7D5FD37F36EC4CB5F +957D4ADAF91850A3B1A765E0E580EDC77556593D1B2E1C22685268469298688A +45C474C9D0472D019CE1E83F25182D084AD85A49C502E8D679C227DA8E32045F +8055D1622C478F8FDA342685F858DE3F53F1CEA0D70BF3FE09037D981E9E7FFB +BC3F896535D0DCF53F4C85A1DA5D0B632484D1F25460E3EB38E251D2AA17817E +F3B25A2A49C0AEDE0B89E277F52CBF744EF0243C409FD71FB0C574640CF11599 +117A4F42F27D8D282D34485AD116F7E753A8DEBFDF7C552A1179C02B7A37782B +743D0DF85C15A333BE9EE82C13DBC9CB007DEB5900954AD9309902E08B3D5BB4 +E8414211B971CE8B9F05A61C15F400D9297745F606C6419E8A8A9ADCBDC39243 +617EFABFDCF9F836D14411BD72EE19D0BDE89234BF7D52E7A68ECC952FB74FE3 +33E1A87DA39AEEE9E90406E2B1CF3799C63E9BA858D54F38918B814C0DF0B696 +839C820C26FB473ACC5C08E2056457A74123A398806EECDB427BB183F5458105 +2B66D7E1FC3529025D3243A045625E9DD9417FA089B3C7C394D2B65C0367FF73 +79F17ADEC6B5D27A5D3D3E244A0839E38267ACF07B2D994C2B4E7F30A416EEE2 +D1688F167D1641A72A795B1F4DA3350F75AD6D546AA118B5F8A5085F5794E6E5 +28256CD31D250D8328C9620B8ACAB03E4A33DB4595E959F4D0FB1C8CE85A710E +22F1940067C036A7DCED7EA48F1EB81AC4735FB26A249A32AC2E3E7636B32D31 +7D76FBEBA106D6C67C94A3BD4256B786B71C6EF8D191CA90CAD8D2EEAD42C6DD +8BB4BEA7DAD4ECB6E002F3B71C2955A5A401E34D55F755BED68178C270109BAB +FA0AD848347EB977325530B27180661A59447D7DB55A62D65309DE24B6638986 +1D3A539BD37E74C2C00DFED3336B5C6B28D915AB7188FFBCE3ADB3CB903944DF +1BA5923A1C053D4682BB8616F44E81E18DB2B58298F4B1A6289CA993DF3E7C73 +B00DEA3A9B747FEEBC4A11E5B9B8B05CA2709B8AA935A42159D3DE399544F5AF +AC1CC00F6CB94AB69856078C9A2EB2046BB9055CDD6A0622112F7D3710143F1C +20CD8DAB4109CD47BC00EBCB88314081C1D6C43132412F261CE0262FA28DB7A3 +C7D8534BCBE1A60488EA230DC558B73C72AE87539A9D7E28C2BE05FC05F58DDD +87117AAF5B799864CF87936D8C1D8F229F9A360B4723A4F6E6CFC14D8D081A57 +61BCC5204486AA325A1D0702B4FFC27565B56069E5CAF5FBC39BB735032DAAA5 +5103891B89076B5ADC49AC614DB9D0F82A2ACE4CCC9892759B5AFDC2BE3E63FF +2103FB503BAB18D54C04E3AF3A1E9C199905484BBEBD53D8FB22BE2919C0B9AE +3C5AAF0F5940C2AA57AC3532C0B547B2E1B3BF6484FA2866F37CD143CFAC6417 +AA7FF279DB13B39E844BE6DA2DB80BC0F4BA660C8EC6457E43019808EC06940A +BDBECA7AFAEE948593FE4C5AD741E38CC1D23CB349B929CF104AFB819B1F89F9 +DA0E0A9D8EBFC19279F0D9846761EE2B61F23490C1BFD26C8AD8DB799677ACD6 +51AD83D4DBC62B0FE18C7804BC707AFBD4F2669A99BED67ECD214CC6217CCCE4 +DDE2E149D4A466A3138039BA0C8F4C9F1F7BD0086A4CA77615B50B1DB2A80F4E +391C6861133308ADCD02190D53C890BE3D0368CC736CDF757C73AC104B58EBA1 +0F4D8C46B0400AA8503B38A5CF1D6B54F70BE766EBDE7362FA8ACCF5FE9A538E +2EB2658A12734DE9426077CD13729DA8AF109ABEAA64D17887D925ED72ED9F58 +D089E9D50102F9DED3B8F858B9CCE4FD04CA1BA7864870EBF916808B2A68AE0B +C2F547FACA828AEEDFDFA3D7FCA3338ECCBE2CDCC0BCDBAC1D91AF4EE4012904 +F1D4D2C9A15FC42F6DE869BF3094F8DE2F6C336B9977C397DEB5BEEB83E105A3 +FC477FB6BD0E727B3F89474CDC2404A66592A55011DED59423489118F62DB8F1 +4760C507A86705D5E9E4E0606B64758F7DD0793A45567AC8D0F99EE9A88137C1 +E7500DDFC30591DAA9C94A74B2FD65D859504D75FA3901C678FF05CF5A035C2D +C740B3E6B815D03E8F6A9D6DADA9AFB6656EB9895374C53073BCEFB216A01CC6 +E87D16C8CB0EC74AC58027A5B4F73CF56CBFF6CEFE6DEF59A5E54D0C6765F00A +D33C1218863327F2F14E1F08861FC023063709F63A76F9C862ACA8584F8FAC3B +F6798B2AE45213FADFE5C32571DA3405743626DC54EF027F91587D94A42A2B2C +41AC5BB2693C322848EF44ED3C70E9E4988C1C054E4E27CBB3BBE9A4BD7D9290 +2E0DF32D31B02CE7A7153741A9769ABA61A44C02038FC185882EA1F27A9EFC2F +5FFBE76F216A814D3C72591AFFD3253AD067D7AA837837C90017DB16664BE608 +D6D8F7F1BA7DE941C7664CC5B4470642854F11E65C165F74D1C0BCB35E127784 +DF635A049A3618ED205588AAC1C7C46EBCBB96B620F97FBC9AE717FB32491CC3 +D7141F8C9F6D886EC55BA1D57A32CC92B7ECDD4EA5A63F70FBB6BBA8D6E52F7C +DA8FBE1C18F252FC30E1883401A741A8C3CD7DE0A91AF9C6783C7BBCE46551C6 +8907EB1831C25597A35984136B1A99B2AC7952720435930ACEA7E2F8DFA44058 +FF9C466FEB38D913DED70ADAD6327B17527652EAE28AAF7AE33EBFDE248E7CE9 +D89C70C005184FC31BCD4016E16FEA997EC2006160627DB17ECBAB0466D01EFD +530482183B346E55E79087BD569B6AE159EDC50176BF355A6635EADF1F85A6A8 +CA8D7AA991D53536BFCE1E94B9CA424AB0DE5AA1B0E9DB2B708B411421C1D4D8 +BDD2F922B044A541A98857EEE0F21DB7C61932F999364F4FE5D92A55DA2A7DE9 +F628F15971B5EA91CE95B0619BE4F6D2461435176FCC692E0E8BA17C240F37F6 +A9C8BF9351B320836DF118D00BDDEAEA9F4CDF06710C0D35E173E68A7E1D9A1C +40B2076142ED236E393589B012FC209CB5A75B98899D90E187A168DF20A011F3 +6FFD0DA23D5D7832A63E9E2EE79138DF9AA7EFC4ED6804216B0B6CE04FBEBECD +BD298E24BE7C6DCE310505C3819D83A8A250C1AF89FA54261A49B73AA9D1F15B +D2CCB0ECC6439270F0078180985DDAAF23A9AB9C024B0E5C0EC41C174EBE6209 +5D988CF1AEC859D008B723C9E40B0B245E58770177B144A997E393875EC59856 +968380D9B9BEF2E2675098DC40D01ADB674968FDDFCF71971F8608A56337A3E7 +694A317A001784FA29B66380DA0D46B0531FC5EDE3A0987498EE42F65C854024 +408331338C211319B05C5F0188F0F5E9C6210D714107E9E7F0A51C20467F4ABD +EC77903905C5695D3BB6672687B155532357D2F4CC7146037D8A564210442D18 +678F8C21AD784B056D3A1450B760FF35C7A5E273A2BF5DAFB5CE37A099875C97 +D7339151F556A8759090C8724EB78E18066939B4732DBCDDA2C703866DBCC5D2 +D5B55E0799D9323ED6DC9120197EF9AA1040D31BA72C308AF99C7A7517C7EBA0 +23D509B658A403094A29CC925F3E4F20D2FA22D4E3D4DADE685354574990CBF8 +F709267377DFC1770516286D2F8000924002248F009CA007511B4F2C6528AFF9 +BF214191ED2445B06697196FBD92801E760CEFA9E04778A8FFC673846ED02564 +7D5E1AC5C743F5901A0CABD59CD3B17ADF721716272F6931E362CFF87B13DD9B +469F8BF603050D72D6828BB83C85368C065A65671A6BF67D6834B2553C5A6B09 +61001B69A71888E196805075304B0A4ACB39BEE94EEF2D7D4CD109313BB4126B +8C39D06B0091618267BCBF89B80E3D2832F0FFBC87542439F6B2735F0BB7E33B +FA43FD59EB2591C87AD3FF107518284E5EC09DD0447E10BCC62AE1AA655AAE5F +3BA089B4D50CD4B1E409DDD19B8EC08BFC199CA6AF9713EDB24394FA1E506F29 +59B336939853B33976977FCE4BB6DB0D8812CCC2404248D54C17EBB131A050F5 +E7D6A39743F427C18165F47E96F89347A779A0BE44F954F80E264DE749B8D169 +965714DE9D6F336879FE9B9BB1B7D56BE831F4E1AE480E242541482E02A76BE6 +2BA4A4F6FFD1C43B3E52ACA1339E1327A04DD6934B6436870A6CA3269256DF7B +903665FED76B5714DEF8EAD253420CFEBCD02E55622C6C1C6B9364F2A670BC38 +18CF833E7B27A6875D827D9F726C7838C91FBE26372E7A1AE903717E56EE9074 +7E5ACA2816121E9FC03F5533BD01F0C56FA3D4C4CBDA69CD48659D91E45E7089 +9DDE6CCFE6557472FA36B1ADF1A84CD5F6324B586E5505BE43640481473FDEE3 +65F6E2623FD9EBA7E33CCE5287084C86EFC44FF047D2C2AF879A6D2DF969C5B5 +71A8AC59EED48559A994442460A4A11A924544C3E732B5EF1AEAA50E69CA0A51 +9FB58785B9ED758C6EB259CEE8E33D7C07764719A586994070F5B521AE8E1653 +476B413DA42AF6A60A085EB76B1548383B9E316FFC2889676415512E05226547 +A611B0FDC256DDF3005DA01AC335803E2B2D4B6138C050E3F06BDFDDD47FC345 +4147FFE0C5DA4408903E503A86D136E4EB13613F4BCA7E466EE5CD0306176554 +722D2C491CBC2BEDF5A69E80501E9CB867C6BACCFCC1C8AF0FFD9D32F6C28C63 +544ED2BEE12B044943EA20447D66DD9968847CEF4A157286D12F3D86AB600625 +44812C1B6B5F646A3A3A3948E7E9A01A49F304E23FDCD0F876B91421462E8D41 +280F26E4782D447C6206015A9D98DFE23C3AF2CDDB8A1C6306E9A148963A3533 +39D1D75B1D7DD5F6B08DDF5C37CD45AF61BC7F0DD0FBCCD6EC579F73DEE39081 +57E8998E8D01EA4EBE5D8640B56C3DA9092A5211C683E6FFD13EA44FC8661FDA +A2CEC234AA27339EAFC5583F43FDEBA1BE88415F17979E8D51AD1AD75B072322 +BF86B7DFC4BB2E771E2535FA00C727D9B7ACC3421FFF2807DA514A8D519FB740 +599F5EC37EB344BB51348C613117AD29BAA70F9191CF9FA9F4E8B4AD13E37990 +952FB2008912059DD9227BD39B835A3470A49A70C0415BA43B6C9663AA43AA8A +CE594D8D204843A71ECC110C7283E2213A1524B99E7F0AEDCC4FAC27F6120ADB +650BDB994724B03916DC8B043B42D119ABBA1A232F1E3414E23C844A460B0665 +AF8A038A492D3B3C354190437A50332874683C67977944E9635A54E96A6B8595 +FE850CE288D9B226DE8B1EE040E38834CF559EDD6DBDD2A351058F9614F1B600 +90E0A0C18603771C5906B10783F6A876BF3B3706C6159D9DD4FBC416D4B704ED +A006B29E7582CB506FC4606F135FB5CB56AE51D18FA9C375D39D82853DB7F9B0 +882212F094B990683982616088A272F840671B57AD563AB660F2B0CFDB4B8C36 +25380A35069C0E825E26DD54E1AB48B8A96EAE24F859E7D83716664884CDAB3D +D3F6D2405E3A73D159EF2813E3E88AC20654996676189703A2BB369B3E4B568C +207094278DF62688422A20813C88D7D8F35B8A327E8A1AE1F7D4A8DF782F2E6A +0D18EA6F726352EBFAFA20D77BA3C2258AB1D54DCA238AB0E693260D2471AFD8 +F7D20457AF5600818335D3470F785F2F8E57897FA182909616256786D1256D97 +E184D6C6600C35694DA9403B6F89E54A30DB491CEA717225D15B87366F09171C +EE79EC088C9CA7A879323DB4FB108973BFF9075AD9301F9C118376CC1541BBBF +F7E6B3A76ED609A5C4562FEFA5B5CB62FB3F1E7371077B51D73F11B1F71DD466 +8EF424D0FE2104B62E544DDE157392C20CBFD6173A00EA14A093ABC28B43E26D +399034D9DFE946C96A116FC068304606D5035A17CCAA3150D7D6224179E51C0A +73B15950EB0AB4E62E46989C5AAA58E79B0FC40FA0EA56B77DD595A2F9A9A616 +131B37EF1B8CF002DB02D6FA9B6ECA7957ECCF7EA8CF07ACBA10AFDA8E636F85 +60F418178553B100DDD39C8830CAA492C88C8784C8EF46DD265F8D9764E03AE8 +305AD1F3C9883B5FF01B5AD8805FA869A0D51837294C164BACB0E9AE1E718829 +2E8409F14B5973189FDF3D3BBC33063B3237D1820E5FF5A193156E94811D3CEA +A1812AA843550BFE568E58CBCFB2909F80DD71156E26C690942A92DDDEB74829 +E33AA756B843765F8A6637C1057C3D7930BC2B2A9B98222455183240AD225B77 +0D07BCFEB9A512534A8F03086ABB19AF0AE2DFA4E176F4BD6E727083B7CA0DA8 +89CF99D477C7974CD09C7F65E2B61F7D5BEC3B0BCC5EE1C28CC1FCB063030851 +E8DD245DE4C5EA00FD4955D19D72A8DF72540BB845C12013FC2526525B8008FD +012D222AD5973422B1BB061EC495A3F49302EAC9662E1738AF548BBA17C9FC23 +63E61D7DB5996A2C034BA859C41F56804D26F459B72D6E5B66D869D7AA17A71B +DF54F932F20A8AA564402C4FD6A94202CAC921F6F7AD7A7FE2B09C54BC4FD7BD +2986E7476A793759A9893BB09F2C5F1B33293F0EB0D03C5F153E53F8E4CC1431 +B406B754684079D3AB96BB93873E610C4E59A25B4E8B18AF291172765E11E025 +D55B90E9DACEBE97048A5CE9CD79FF4ECBF575BBA968C5B9393EE8CA465B1AE3 +9BB58AF608331D9BA6F82D9BDAC77DC4CFE3BC4B1E4180E1EA0ED503B52D394F +2EA5750F365BDF580D902AE8E257D51A2B7E62115EC33F962DF2179BA6CF28A8 +C54C737C5CC5F7D7ED533D45D25F7817154816EF089CC3A9A08688E9E5DE4D49 +56197CD7A026D9E51731E4A5AC940ACCCC225A2169C415AA3E70FDDD37508837 +6DF9CC8CA759792A1E821AEAD40DEDF15E511F7DA04535C2DCBA4BD2D29E0318 +B7F8EBE99BB004091343FC911DE65A91F12D6176E545BC3DFD315EBD5FB7E4BA +9C258361E1CA7282050709DC83F3C65A7D180A6F236A3BA775B81FB8BB944AAD +9A7CDD1E68C6317B0A5AAB473640F7643152F980E6A55AA2DD648A7212F876D1 +7A12A91639DBFD5C4252E8CD18974E4B73D40E87350634C53405B2371EB28D31 +9E1A50186DB774062E5C4B2CB62F29DA8AD87714998398D069E8BB122B2EDA75 +BC7BE20D51FDCDF7B462FC1D54C2FBD436589D06422BB5F998BB443B2C9242F6 +07A6F63178247D90BEA95D2366683ED790819A3B83A48CF0F949D2159468F42A +66494476D3539115553197A6F4987D24806FE6B8A1A2A77ADA3D032BC3BD8150 +9A82E967AA51A0247CBDBE6B9270C165C4FF95B419161569BDC07F0872C40408 +8CEA68275621E4811928C15AB1F2FBEEC2BAC2050D2037DB0A502EF055199110 +96E4291413CF40CEFAD61ADA078CAE6F66D899FF08BCD9B5666D83C0C6D6FAF5 +1FAB8293A278E059E3E60CBCD9C33DAE7370A258FD8C7F082DA7E1CBCE8D5126 +61C9352B3BAAAB3BB707B575B0376738754E9A48216092E211AED43EB5CEC4E4 +9453241CE8A8F9B0177CE62C7766058D2B51F7E3F7B14A55E4088B3439304496 +E76A698022AC902CFB69E0CF7D0AA41A3ADB1F5303C43BA4C1F8EAB2860C0D90 +1EFA40D964B4131397D47EB43681BE7C4D4FBED162F2EF12898AF86044563F18 +4F9758F5D7FD7F00B8383FD49EE983704BE7D27978EF522D3F753EDDD66CF16C +801649B107DC2C59FEBE36AC87FD44D13861A384CA0F83D60B217C30C2872921 +AA4B10F2D50FD6607F6512259A4733D451B7ABC4EE20D754A876E3CC75232138 +B8331CC4FFCB9E6A54C863522E348398BCF299EC5882BEA2057C4E82FE5BC8B0 +FCFAC22AF8311CD9F60A2BB79C794A8B545E54DB04441A78868D012C1174777A +9EA8715DDF3D1B3A5C21D2CC73E640F5E6D80E8F59DB16F41F0D213CA5DB9744 +5EE4D2544B542E6BC2EB706BB4AFBDB1FD7C53ADF3046419EE28D18B85079C25 +15A287BA17BE49DC02274837BEB76960CD445F8CCA9DB8C10E1881157A59749A +1BC36D60F20EDFD3C81C03D9C2CFA56F7A6FDB1673B0EF6F02967246D1AF7A82 +CFE0C19DF0CCED0FEF53DFDA9E2222FF564D68978479279DE87A09F8BC44079C +AB58599DB3B44D1BEDF276F71D45DBF5248D28A91249B4CFAF9D5335109D4D14 +07C9E403468F0A6EF430F0F5F5D27912F18E634CE711744773562F3B39A74D49 +CD0082DE935ACE54F297762A2CF153DF4A1822EF2E154C6A9BF89F0BC9918D49 +3332D5CBF0D2B47831B32327A2200983D9211C1FF825B3859E0D2BF847BFE94E +6B241B26874458D90F7A0DF6E31EF515916AD63F784CDE8AA4421C7114D1B579 +4350511DEE1697BAAD53C10483B0B21D41A42E0614F18033542D3AF3E8C9F4CD +B181EE1CEE588278A44240CD360D2376555ABC6C9FDB266A29AAF1E201DA1246 +7660CE02E03F12933E53A51368B2C03F91725D47DF5AE460E27BA173ED86222A +2DE9D82EFDD1E60FE94125E322ECB2D45158D2CC4E2B6971DF637CCA67172070 +1A52AE7FDAEB7C851AF96C4176062DB218054E6D54864A955112D9248D27CF1C +D824ECDF2363B50751DF5519D041319E32D146694510288D8AD8DEC248782978 +E85352191D4FFFBFF962F80E4AA3CF83EB6BB993114E24CB1D2AADC6C24D540D +302A3A8B3BED5B83A7A7E5D49DEC968AC92FF84C54634808EEEA382B017C8D35 +8B6C0BC2E0302BEA473B9EF4352ED1D270D5454D422718668C5C723CD46FB700 +CCB796D5FAB9ADD52818BD2CC32EE962160329B4B3E665C1FD125954DA22718A +C7B6AA9A7B989F7B7676D649610840615383CA2C7E22FC47B96830ACC93AF4DA +9E3CC26E6C440E157A39E3AEB46413C2A34E00F51CB4E688815AF9403D78ED27 +02A5747FD9881DD48FD4B7244B57C3D641C57D4F8DD821F237B3F96E41E9D9D1 +C614DFD804340CB7762F8EE6D42DC52F9227CDDF964CE3107D707D0BD887A242 +D5DFBDB527AE23C39123634D0AB0CDFB7458C47D6E0F6A7CFEEAE2F349208B0F +E3DBF18E57C4B509E3B43DF44FA34C5ED174995280EE2BF975FD8BECEF64463A +8A2A6D8F248FBA2036DEEF8C416EDD6588717E5AAF2A6A33361A41DB916D6D39 +ECBB218CBFB3508D8B79DE1E09FC7E78FDB8BBCE9073B07E679C2CD32D6A8441 +40556D5723E1B6EB3745418677BF0B36EE379CB9DC0B30FADCE3723A42A628B1 +EFE1B566607908F19E0EA0CCBE94CD74A14E6EAD55E28BFEC848CCD0D6380ACD +5FF3EC2FBD1EE4B096D4BB4BBB6DA254ADA2BBE0F17EE44B91B70BAB4E7BB33C +52DF702FE333761D7C93EDA68F6293B633A4B56F956EFE03C04AACA2C9CE99B1 +4346FC24C9522F7F02B10509B1841DF7737307F458ABBF7C6020CA4D1D2EAF02 +AA4BD629533E15693B5FF63FCF0962315DA2EE5A81A0969F6531BF3ECCBDEEB6 +10D2912C87F711FF7B89CEF50ACC2FBDCBA7263B9F45C98549ABE4CFC4952C7A +12F799FBDA0678D9FEB0115BF8FEEC34D765B4C523F952694A62F8F5B1F777CD +4BAA37AAEFF0E85EA76214EAFB36E4901C28A21FA167766FA5F7FEC66D1AB9AF +F301FD16C490DADC372578C2F78E0319A96E7E6CCAFD3E10E5B2128A895C05A0 +3EFDDFFC7925B298434B3AC5DE258F72413F6C360A62DDC17858D06FE8155CA9 +1AC8B05577ADC56CAFEF46CB8307D48BA2F85E01235D32D6FFF63147949F1623 +6284CB613541CB23AEB78D1829F8319DE59CB537266CD095F8A5D413844A9883 +2102DE6972D49511E798982BBA9A80A3BBAB5073A9676AFC39CC1C9719894981 +014372D8161D2988DC9248D98ABF4F20BB82AC7F63BA824B4B60D3AEECDC9554 +803218464B392CB0CDE9E6BBA3BD830A186733CCB458D23BF42FF8CE22EDC03B +1ED45E98EDD497E64F32212CAEFFA1A6CB1C6AA5A5EC774C924A699EFB1D73A7 +9A0C8C2157FC3E675C1FD6E97E5CDFA81B206D96C091B4D43EE2F2903B1CCE69 +7FA7C4C3BC69D7C31AE62A9B1FF7F0C229BABFB582A2E9E0205B0804481629DB +F6DB901BEE12766CB079B430A21C8B075F806EBCFDD07CC5EDAA22DD73B58BF3 +520611A09D30127BAB6534EB0E8153F5BB415B15C429B0C7C8A1B13F06B82316 +9E0DA96A1719ECAA4925C794852971BA9AA92607342BF4CEB8129745320124DA +041180276F4E1B24F9EF6CFE34E59F1FD71FE6604C7815EEA94B054C0F676C64 +5BE01902FBD94B2008F813F650B2CB87A4E6EC36F052B61B9BA890D63C07CB5D +B9B59C6074FCC78FFA9AAF977E88A1C9E31F731D8A4B205FD0EFD75F66BF92C6 +BBA470E0D392F752FF6C4C9177EF8A271A15B4725A00140D4E18CBAB8BB9CE25 +38FDE189A81FAB1E17684151DF7D3B0EA3ECB14F5B78AE98FAE563246B4FAF3D +594683B0F7A6170561BA0567D00AB2A6A1F144F7C4082A3CE3BFBF5A2D9F229A +C805B3493CC68E44D29D64E0A4EA9A42E3B30BE011D9E8B59B5D51272FFB4DB7 +CA9D4DBA93EE852EF01B0512FEDA64453F6D7CA7C9A8BF0391DB6474729C9D4E +462CEC7A24B7903D11AC9DE578E6F93BAD261BB6EFD346AA8E849BE5FE38BF36 +ED482886C844B747D6DE5A5F5DE4C69E2F29998474B04438BECF9AA37444E73F +03707D9C96E560A4F1955E559D2A9EC1341D16847EF32B687128B7E5A4BFB67A +DBF85EA6AB23B01C68D4AA21DCD51FCD7BD086E61454B232EB1F65602FCB5C30 +A5044ACC5A571092F381508E86C623B64D50B5403AD390B14B0A4092E486C941 +D72C86EAE3218A93717E11ACE322038ACD091A1D949EC366D62219D635113F7F +0D6ED7977F6BEBE3B41946B0779BDA719811484D8AC8F46341E40C8D6B319A40 +105215CB1F1456E6E17B4960D65B5E1B36DCC11A166015654BE726CA6C577775 +32A7344EA7EC4D5A831B00CD0602EB8FC6A14E09B14E6ECC19CCD2E62BEDF56D +A408361B92D81862304991D50431E12F8A2AC01C84CD10BA3039D129051D2F39 +0147B799E0701E5553B7EE077BAB0641CD20B0B9595B68F9BA304FB4995782C7 +A013C8F1E2A894B2E250A576972E75D9E11F41F42172EBD1C2172C8C98707A16 +8BA6BC35BFF113DAED71F37FB3013050382E084A8296680FCD5923309652BFC4 +457D7175D7C409DDB37B93372606AAA50AF81C447AEDA05469D7A9E7A17E54E4 +DEA417A68CF9858BAE1C513522EC43FACD973D5257A459EF317497E669B9C192 +EABC1FD052F67FE686958404B7F59CD4E1101CD6F7FADB53C8A89BF56A164AD2 +2A258D9403782314AD0C1F88854F82DDDAAFA5676FF045E7C486136199C9E69B +58D1923048023B3BAB8B9FECE8F29F5EFCC97AF5268ACE49AB4046879D6BE232 +553A37B62537D2FECA5546AF9D1DFF254F589296BE5BD83E2D330B6F0346E8EF +D30A2F6C0C95F3CC29C627EFE3F5859885A1C8175638EE5C492425FA18DFEB0E +0C8611A973C89F89659CDCADE24F74E125634341399044C127E15964040049E4 +D45D258DA4B24EC2583F4E6F11312E3509B79F63D48FBA24EDC0953319FBB422 +1A11DE672665565935C352D053BD41E89C636D298538BB936DB40837BE605FFD +F34C6C7276032AE06DC45D20D0F90B005B7BC933E31FC30A85EF36DF57BF4907 +60E7961EA6704A211DA5E7C942A341ED855CE1AF9952C07EE8C69420E8F9D206 +0F449663002546D4F577E541B9F2F4EFC3709BEB795C74DCE1478EEB9969092C +5DE3201955463A8A5B8E1B01066BEB0E7B632722B7C2282BBB1F6A3D00C2CB8B +3EAFBFD3F21A91A283EA4005221AEFC214921C0804D8ADB421F7AA02088A7FB5 +868B0C9F6FB6FDCFB6A086EC96F1B87713A92FD0388686473211F41C21E67495 +2251C93C9047DA84C5331C43D12B9F1CBCB57A2FEA713AB3C60F156FD90CCFFD +F6273168E66C02F571CF8F577731706E37961F80E2EBD0716B8DA97561289E16 +A3867372D086AA7109E40B7E4082464B95F7CF509513359DBB881763863A78C3 +4CF0F4D15AAA18F1D32E3BF65015419F773E6C438C1A3B8D82DB0737BB6630C2 +92B04938B0D982F072030D54A8C4DA9C0ED7EDDEB5AC355F42095C07C312DAD6 +37C5593CA81CF1D44BE2EA00B573D1228466CC7B30BFDD73366FDBB661CFFF17 +BD300F02B7447C47B068ACCDFCEFEF156E0A724765249A8866BCF1B28DFCA692 +128004A0DFEB6AF5307B6E269F21B8B83FE499722B8C603BBE21743EB6A32348 +1C4489D42C20BDA06C78F9641F0415AC8601EC4ADD6C5B25E38A4EF89D38EEE7 +37C352074075331CD7B7FC6E26A6EB9F912476F1C997D5807FAEC16E3B8BFFD4 +0577F117CA4E9CA784CFECE15BA18D8855F08CF47ABEF7CAD33E7107C7AFA833 +D1368167D4B080EA93B8A8BD9D98522E65EDB622B79EB428BA1C1B1550E109D9 +17982884605F47D524FF901C6AFF1A6C578E716B0EEC5FBD54C7FE7A03BD7DBE +78924A1790FC3842D2C5ABB5E4A53F1E2E53F7441D353B1B6BA36D821867E938 +9B977B374594D863362C81DEB4F003230EE5A4D1C135D67EA04595B412885A5C +C02F5F80F6DABA797442D7A3C6E0BD0B9EA1695F9EE4D6A9EC63D8625C922E5C +05C87FF4EFAC2F53E1960541ACDD2B8D8514EE9D0431ADA84804175296A01C38 +9D780A8D571884855011EBB8A945CE92950DC7671E40D1E6D148E219C2D8AFAC +83A382674547E4922C306BAE3B3F8E5136D02DE01C76546165AF18BF7329761E +22AE7215256ECC0AE80B1161CB5F51F41A2357492B682BEEC02191D0F9BFE958 +A390749438FF3609515118205720975F8DC1165AEA56B832DE08A63ADB469A72 +8C3E0E285F31F58074CB451A43F99EFB50DAC1F40DF9C1FBECEEB328BEF931C2 +5EB0F41E12989CE28660EBEC4D5575A7C42D78C7C78EB886D2681044F33D635F +E04C867193AC75B2A3CF3BEB18E260BBFE9CC7960F8F2A89ECBA0365B5EEFC25 +29ABA3DAA181502BBE90CAD148D139B61BB1A0F807FC41C1968B179DE235B20B +4688F425E1BC6818120039346FB10B52C72E203FBFE4065EBFA763E90C8E4F59 +E5659866E552A011CED8EBE468EE2A1F58924C51ED4243B70103A3DD0340C33A +D51B945ECA8EA610F74A87A7877646DCF008C93AA558C73896B79B9386566D49 +3BC3E3E74E1110DDCB894E5F74B9D8B52C8AE5CB744DBB38FA9821CABC213605 +69D9167962F2B93DABBBDFFE2F10E7528F7CA30382011465FFF1F286F749F3F8 +39D2096EA755B9BF025E561758A853769DD7D2B51F39571F8C1A51E846B4C4D1 +F3F43416F8A2004CFA688E4D40F664455F98763B2F2F84E82408FDB1A650E4F9 +7F854C752A912D60D7086D69282E60030B1EF3C6F32F703427223E7FCF648971 +96EC4BE43AE16882F0C2271D5E57262C0E79FDA84A01F6EBF5163E466F0308A5 +9C43CC2E0839772784DB682C4E6DD62052CE8098DFA722EB30EDE5A1C5CF4A6C +1BBFE14F1D4A6BC68EC3DA0A6AE03A6803048A55AB86678D461CC807D225098D +978AD63B468C616B82FA0A5C84BBFCE980AE8FF6BDCC066E8A9DC791B450B05E +85D1AA94D6AB09E56503A79BDCDB9ED26021F31125ED07250AF92431414D657D +E2356639BF4BBF2DC9BEBE1DE14D61F953DC81024CB56D9D3413423C2C2594AB +ECA5E3AF1400062FA185E522B7CB1D05BF1D4773CDD1630346EFE1982F401DC0 +75FB0A78F6328C00F1E5EA792A595C54C84D02258493633F211292AE84F5311F +B03E7E4C71B75482608797918D9B2B07069730C384D4503D899DDFCB47E1D5CD +F9E54F929DCEA224E651B51EDDE86D97243FDC2210E75328118D0043FC102BEC +36755DE5B061733C8D6CB00F8EB03C41AD2CE61C2F2B9B1FB6C8A658E9A1D6BD +6789379DF39FEB4F03F5D939293935DF9130E7D725DBA6D72D4A88E840934B28 +A489E10A0EE8642DC4DA73BB17E03823E851BD203C38CB3D3DC10280C582ACB8 +A11F4AC995153D370E41CC1BB7515285E1E8025C0C30F3F4130F6890DE6AC897 +35A1ADBE867EE4C460D3DD18BDB5F92D30F1901A62E78EECB18F25F3FC464A93 +AF5E8342DCFF912189EAD3D38CB1C619C2F3D9A7F3DC1D9E3B53873CE1DEFE9F +7D345CAA69F4B271FEA990ADD027EF8377F38F4003C5DB62A23BA2BB18D24FAE +2089EC9B8E6E0546D224BE593216EF00D0A20B22329E883F4548AA2F0A66D1A0 +C8187E75DB813DEAC2D9E3BDFBBE0F6DD8ACD387D868C03F79196792A7C66400 +3FECBB78EE9C29F66D0E29D7A781F69A1C5D2795DFDCE2DEB08FC4660C2BFC5E +7D1682086CCE9EC679A6B27F0242A02645B90AB23DE1B36247FB408A33B29023 +C8B07255C9A2A13F968BC5E23A066661ECE811CA0200046E61CE6F4055327439 +5EB675F192A22B3D2E0C04405E7697A18801CAC1E7F7B8F05558A5835E54A53B +F63688948F9513768233F602DF848C83915B4142C5FD5A303A1064A4C9F884F7 +3EEE1168BB2E7A9A2256B8937E055DC1A201D5D98FAB39B4DD9888B469D475A3 +7C0FF690D8222882C898DA750F263896740662E7FB849DBA27F0C94DBA3223AE +A9E9BCFDBCCE48B51EB2A347DE6B9A3242EE1F7A77B8C31F8C99699CCFF7CF1E +6DA4302C9142A4647687ECE65E8067423DDE14E2606D2A6C5AB5D6C16917F5CD +6946B900F96A3D0E991F4BF6C0F74134F27A1299FBEA46D13A615577013E1F08 +DF2266D1137F8476A06A2A8380066629271AC7278FC9B8E1E92FBB4A615DD4EB +EEE929EE3A9CA13FDBF004CCDC31CFDC3197F88242BB76A611027DB2712FE3D3 +60EE112EC4422C432F29B5434497DB1C28E56983EBC5D718E402CE282B9DB9FE +8AD9596763D086EC098592840E0CB3736BB5D2BC69850553A885E7D5D83A5B77 +62D8C951FC13101D437A5706C1C365E4A39BEB40BE402D0802381141E0862F91 +3007D3CD64143D49F183228F5915A00CD8E0874B2B1869E4F1A05AFAFA684B95 +36B75DCD7AF5ED0E80A7AB8AB1BCF3DDD0AAAB5B0B8C57AE451B10F30BE1D36C +98B3B8B5C309A2F29841F539CFCBAA9E87F4A5BD65A5CFCE2FD87683561DC95F +19556BE0F8A556E63395572A8592C24C5A69D2F70E9DDB4C02DED809CEEF7800 +CD756F30BFAC8FDAE0D043673EAEDEE8203E390FBCCB13DE4E5ECEE4D2493038 +ABBBDC41DE941215108FD9B8863F19561A89F2E6E12D6353144FDC78A95D0547 +87946A3F272829C4F55C36631410C680C9464D3C1769A182BB2146ED8DB95CBB +BE74D54F9024C5992756E87EAB1B200EB50BC6AF9EFF7C01CC445FF697B723F1 +9CE092A221983499D6B1EF19BDE38E1841CA3258993EB9A4F790DEA6E8138088 +2802A1C56741B9780F7CD26D76A7AC0EF1D67A78804896BA2B11A85AF9262520 +4306484ED9CBAC01BD2355507FF24572B4A5F63B1E72BA6EB51D5A83397551CD +3AB93CA1E49EE0CF12FA3FD3F17529819976861DCFB4D095D8448CB60F71C445 +F5682A603D32C59ED871740E2876C04A7B74B46BB22AC8C1322192FAAD2998BA +30AD8841D5CE4078CBBA1A2F0F4DB82E860B486445BEC1DF832D57AC7EA5DCF7 +EDFAC8E629BBE7992073255B64F1E3D7D1D09F5EFF73862148A4F5B4037C4D3C +38FD939ED0D5A2FC75C4B83D49610A1419E7ECFE36B318C3E0F515F8D8AF1781 +0C41C44310EF5D5A8C2CD75672F01CE0D63D401190698CB2B6DA89F8913387A1 +072F6D35750E97C6D9134B5D05A7FC599FF7D01664081CADA6EB741CF6FB5D7E +FBCF327894E5D67C91A6B0E73DD0E40F34A93F0D43A41AC0CF474817B3AFE7A6 +31442E9B9285E0C86A9CF99F72735F22B33B4EFBAAC0FE3BC02A8978D11D0388 +9EDCDD617D04F304B13C886D94482F6639AE9BC810A69F878B82994DF45EF7D5 +D23E22DEAFC4A812D1AE50B8E72016FC3DD8DE3325EF26D18E0193668B32CEB6 +ABE21B71D884BF782BE606EF3B1BB22840FC0750B561377E76CA7920304C3CCB +61974A06B1F5E7D2385304B35932D00C132C3BD51FE442CA198D23809647E532 +269298BA0BC1F94CE51E1105BB26004551D262F1E223BA421F1AE001A3FDC499 +EAD790F01EB439099233B69B1260940BF4C6B5FEBCB49009FE7BBEC1FFBA5B18 +78181D018EFB2BBD2901ED1030BECB017BA70933946E002C68C66ED2E748C4D4 +CADE1C95B8B08F21E621CAB1F4E868C4CA460B8A0236DA3A6DBFB4F1552831E0 +5588A85CD3D88123B6D7E7A8F425C5FED306D439DC5D7656D80B8AAE7FA616A6 +00757AA72D14B712D32C6FC905678BEEDB15A967E287197BDB4C8DC8D4861757 +9A7DD89041983D3C74523206C046043A0583A0FAEC4E5CEF814205F7B5616BF0 +7BD55505AAA8FE85324F6CBA930F6B3D421416446B7AA6BD4035A216CB307B13 +1B64EF720D572A90C2D21CC8746BAA178190D9CF7CC3CD04261A55E1E8A4925E +6F429610947CD4C64FCC6F8AFC6EEB42FC91CD4BEDCD3079891375DC26EA3312 +834DFEC5DB8268F970761CCBFC41F279528B793E60331A1491D4240E94064170 +137B1F979183FD082D80D3D762CBEEE1EC7C5A8C720499AB90F454EDEEF0D975 +0D552ED55EA27BF77E2EF0323C07B9AF8D66BF4B3C7A004162B1CEBC81264FDC +34610D8D409A5C6682BCDCCEAFD7660551D9BE3E3F6BE832269898C29C50ADB1 +B606782DD652B6A6D292D62DA70D1CD18F3350A9494541906AF3D5A23E67089C +D824916288704B2B8AB253D14704603F88E574E7F23D00B80CEA20E32B385AA9 +B8BE4A4EBC0F9E2976B0EE79B45E50F002BC88EE6DE5BD53B477FAC1F21CBEE3 +43F2C09120CC7E969A3A15366906F02CD872AC233C823C3D158751E04E4C731A +A1553858F728693AB7796DBA03078AF0DB3D22A42E98266AEC03C85B482CAD9A +DFED9A85E80E1CE1D4E0E0B5FED748191BB04538E2E34811BFC2345DF34ACB00 +E7850406D64F7A02C1103A52CFC3390A59982C2FB773A8F2762F71A85B1C5B81 +73B4F49B50AA38DCE230FD475877156E51CFB60943295C1A0BAA2C43BBA36596 +13512623B4FF8B06DE20769CAB1F0CBFC8F67B8EF3E790E6B3BF1B52B7987B2C +7E9860C2A39E9F306A843703CE76E10349284505ED0C8CDAE2C749CD79551B32 +BD3B0E989A2017172CD382C10A2D508BC3212860F188FE84C209CC56D35BB431 +F06294DB71F1769F77B8F361CA3A8E21882D8D01CD15CB84A4295AD0890A436E +B16A995AEAABC00E5B7F5B00E8E6F912C986297388E4D6FF6966E2F20544C0FB +C1BE4A837B1D97AF94622520D1E73C1DA7887D0005CD8362877E19981DA135F3 +2F327E3F35D0F268DC51D680C2D88CC0DDEA82BE6CAC6D04C9CF1757179CB387 +510CAEF5BF49D87043854F52C311C0C8C9CEDDE928573F0EF48616EF1453A6F0 +D1E63B51E8E24565C6D2459AAB1696BFD08E9A01D5F5DDE8DEF51EEC635180A6 +DB18475445B3F3D3A04BD1B32F6FD9E2770E03D5029D8EBF1AEA5BE7C5F77DFA +4218B0D9F0D0DAC426EBCAE07D55DE8BBF6C5B7E31E866FE00BF36A4B8FDB9A1 +8780F19EB690F6F40CF696C1ABA4D268A79A17A276F3DC006882047A0CEB774C +D6C83F8477221BC91F20E5F220568B81E61F5A5AA7C8F235E28A3CDB5BFF12CE +D150895572B01B78576E5B6F097D73A76FE35F19692AF7A01164AC849B48BD5B +10C2BF53090D8D68A707F2FE7B0F5AE909D03E839E1570FBCDA154D4DCD17440 +512144A6D5F395286158CDBCA3F38D25D571D92E9BA44BCEAB6BB3857D2CF452 +C6FE8E7EA13E1A44E8AF0ED9E676FC54D9C69C9C0B1D6916E19A077E1408CC66 +2BC79EB80F1F79E35F423BA66641E04B314CEA3F7DBF9671C7C29DBC49BBCABE +43B1C309D17093C8DC0EB4AC9ED4FA714A42AD53B1B9D736B91E3A6B611181F6 +7323795CC325FAC8AB2C9C61A522155F81094F13E956A0249B8F758DCFF095DC +529675156F1901001835E5D4F493FF6EA5FDAB257C9C40C6D670B100947517BE +06A1C281A0FB02C3A39CF61AF93D1C374C3BF28CE1E4A96C81BB0E6ABE4025E8 +9C7C206B3876AB9FB380006D6E73FE0BF40F4E9BAB3EDA3C4D2291A170086916 +54DD82E8A6FA0491AAE56EF41D04B88993D94E3525B60800C3817E5864083AB9 +DE3634043328C0B1FEDD8D8BFAB353309F1A3D2EE0C6723588A37B92DE734815 +30485E14B3CE5BB833605551770BA60CEC13C99A45F88A2D084F99DF57F3AD17 +3055D9B8C0F25838283429F26E9F1B03808B3FC3AB19D34308AC0F5EC3C13844 +B8C3BDD50B235002A6606B6293CFE82018CA6961A5127BADB01E33B5D21B42D4 +84ED4B6A31FBAFA3595D4919CDF092A9E582C73D5E4E1CA7BE0866496F793DB3 +B933AE410AF93E5F50A532F05CFC2D1BCCA47A57BD840EB4E2227301DD3D6EC6 +0D07EF015A80BF1F43722D5516BE277993446A7CAF044175255CC9545DB7912B +C937FB5FC9A6A8E506C73FEAABFB6E0B4BD45C3CDAE23FC91A141C4A0AED99EC +CDF184769E6279B1D62628F82A33E4FD0B9640F6DAB5A1C73E67C080E9D6C06E +267791494AEFF512E674A8F4072CB399C5CE0949835D29E5D215B5A811C0D8EA +DA6C73556553B06B9220E6B4A69D43B1417A2777494C08C440E1830F2EB2EE5A +D60D22CBE2F8B1D3BFEAA18E7041A4C00856E1EE214A3E16FAA7239D707D471B +6688E7FE83B3CD6F564A40CC01831F087B112CE22B8F9F56F4BC1B49CA0E3B79 +B7BBABCA8ED6F1D48F70753339ABC9B1E9AF5EAAD342F7BF63E16A579ECB04F5 +19E51F41CA50AAF079A0FDEA1B2A6AECE65DEA7827B169C7FEDF3115E5392F40 +9A95E752D0EC737F96EE2947BEBFBB6D41584C7603C1917BDB7E54DD519AD614 +C4F4041EF03FBF107C16596A6D1659DD8734C3E73BB4A9AE7E0B5399DA417A74 +1E16673F694D68AA658C066A75DB80F090D1E5685DF79E578D031481D25E2594 +D559EDB938A0AD499AAD94BF5F0B24F78A5EAA47AAE4BDADB44F9F05A3F6FF05 +0161C7F9727D2C2D35722E6658006D2E76796CB81558269018E0E5F8CC8721D6 +1C8FD93089CB16DD3C74881A55529E4BBDA2D295D054A3CF5C3B1DBD49B7FF2D +45DE932732A655AECA4E13219E72CA6CA226F16E554C091CD7EE0413A0644264 +C28F40661EC51EBD8FC3FF5333F76B429B9E7A4DA5DF9AD23DC69AF9EB83646D +1282A1086F10F821319A4CC50778EDB44AD993B23F38FDDF1234EE7EF605BC98 +0A48FE6639E76A5F1C694B24DEDC10D4D564EA4CAF6DE86F5D0CB85332F040BB +8E5A4FB85BF69D2C14A0B50A1E8BC8317945802DBBB88B10304A7F562A00FB0D +5CBD1D16C44B2D162A118629421E59A25BD11299421988C05BEA153CD63062B6 +00595D6B74698C6E5A80F18619738AE9035F9E3BBD450A34B7EE494260BF6A91 +4B6D7E57BD408DFE45D9BD7A0141410C701ED97E7880A30CAE564ED0FCE45E0C +5A973F2D1840095FE7814E870BBC481AF098771BDBB1AA3BA12B05CEDC1618D5 +A4BE996306FFB4A82B4A9B8219B6FDD1A862A7271D1D1778226791B1522F4636 +060D74FFCE49FDF8E8334358DDD9D44CD22CC91EE6B8B34808D3EE5CEB29606B +69298085303942DD9AD17FBED4BD5F879ECA6B01513CADF7EB3CF6A6F90AD4E8 +49D97FF4D2CA0B4DBF3E2D7D190F801443BF5B64BB18F45B6449A21E6F4E13A0 +25476AC1BB74C165D5158181E53989A68882912FFB9D0A3296D1993B78D6A66C +A67F4D3E2A9862A341610C56339F440CC582219A628A3DD8A8AA66D2C9EFD995 +5B1B0CA2D5BB79D7A82B9E44786816C32EE51EA8F9251067AAE67AF57D949739 +ECB3A0F79F40DBA21EBE2350217DFCE154B82A4A533F3EA1FB5AF46004A71700 +BB0AE56FF21E7B4D28DD2CA9467E846FA69C6A7C0FCC7C6ADD7D9A43AB523349 +344A909CAADE967183ADB67D36F2B44963C7F2ED730C6723898C84CBEC15A3C0 +FAA838679BA20F676E40BF8D61752231123B45E530EA8B32A7271ABD0BEB01BC +AE011B8CAFE69E71D5C07CED148ABC12FACA5CA0842F5B3F7B9A059984DEC18A +A8712CC17D6B8E5BA0564F58179C668ED6C444FC9EE53E655634F8F641656CAE +63FDD89CAA88B477736AF141C71E5579566E70CEB1565D91D69AD2E3CB91B064 +B93F11F873F88AA055EA8B0A001C8A1F518113CF19EBA1A31A7CA0CB9E7C7426 +214FA748C9934A1682CF9E2DDCB8D499BC +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark +%%EndFont +%%BeginFont: CMSS17 +%!PS-AdobeFont-1.1: CMSS17 1.0 +%%CreationDate: 1991 Aug 20 17:33:59 +% Copyright (C) 1997 American Mathematical Society. All Rights Reserved. +11 dict begin +/FontInfo 7 dict dup begin +/version (1.0) readonly def +/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def +/FullName (CMSS17) readonly def +/FamilyName (Computer Modern) readonly def +/Weight (Medium) readonly def +/ItalicAngle 0 def +/isFixedPitch false def +end readonly def +/FontName /CMSS17 def +/PaintType 0 def +/FontType 1 def +/FontMatrix [0.001 0 0 0.001 0 0] readonly def +/Encoding 256 array +0 1 255 {1 index exch /.notdef put} for +dup 45 /hyphen put +dup 68 /D put +dup 71 /G put +dup 76 /L put +dup 79 /O put +dup 85 /U put +dup 97 /a put +dup 99 /c put +dup 101 /e put +dup 103 /g put +dup 104 /h put +dup 105 /i put +dup 109 /m put +dup 110 /n put +dup 111 /o put +dup 112 /p put +dup 114 /r put +dup 115 /s put +dup 116 /t put +readonly def +/FontBBox{-58 -250 939 758}readonly def +currentdict end +currentfile eexec +D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891 +016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171 +9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F +D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758 +469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8 +2BDBF16FBC7512FAA308A093FE5F075EA0A10A14816D516A63DE166FBCFEA932 +BF000C3B84394CB6E6A446D37717CF8AF9A27241D89E3EC12BBAA36A87DA0A50 +B96DE87FD2565D6BB4225E150CDC8FBE654B16102FE8DF3BB5EB869ECD8E521D +74ADF974252C93C4FA50311485350B2EC0A92EAB44C9A8BB11852B3666C5F393 +6BA5AE3D742F26EE549A603EC810A7528CDFC7D3A1580528936A7C291404D23C +A573D08407861ED401CA26626B04DC86EBB4547870BA7A03E49CAE3D0CA7BCD7 +6C28C3A89BF4182CB84BBBDC9DDAA541448456EAEE89E87C488851D1235F3326 +D866CED01587D10C2464C07E3DFB71E49317FCBCE83A4B85F2B7E544BFB398B8 +5BD9355CCF9088DB5108E011959AC68F9A3773B17656F85521618D608D9F6450 +BC4EA327B03E999BA05A16CFC2234F388EE7463AACF02EA3A45D5E65805C7ED9 +4618D5A8669FF3ABAF8B41D76D11F4AC0DB848BA8A5D51CCD6D85EB6BEA99A54 +80CA3DD9B7E9832296073E66AA9697E86758256A063934E0B30425BEB569D9A7 +C37604DF22CD0A369EE007F67CFF5A930B5F77EA030E547DC635869BE5905270 +09C91AEB22772C01412D78965DD2B489B4C4DF35FADD130DF1FCD2C59D0974E1 +4C161E5FF72F790700E0439032D0240542B702A7520469411C6809C27B3AA535 +A5ECD235FB90601C6492C6C3D2D38AB999445474D7E788097E247DE495BAF83A +7F1C70DD205967B579F69E764F4DDDE56AAC3D87CB837EADF755DB85B88EF041 +AC4F754DE77B66B0471384EFEBF9D67DF6626338DE3D4C65A1831032D36C0B8D +C60513EA65E9AD53E4F1F1AE4F6DB85E249AC53396FF5DB2189F37D359DF0AC5 +9369E07ACC443314B1A13CBCDC48DC2F95896CE74E346E7E94D94E7FE6AC0C24 +2C491FEF52CBE382F428BB27C7D751EF448A283714D3A85D77648FD98DD4C09D +7275D7A9CDC64DC3BFBFBC19EA6B3ECD7B4441979E9C6BE0EE0B191D05F3B08F +7AD88563EB0445D2A6AFFB1268EDE41195BA18F3537727141A362DD0D32FD850 +74EF73DE82DE616C6A857858E6B75B9EC028CED08EBE473D2C0CAF3C3B05AF8A +B7788CA9CDA433EC55AF0DC5EA62D7AE4CD374267ED41D48033977FA3CE1AAF3 +C88DBA924D2DC1DC83A2DC5A9EFB036361E35B29BB2A6A7067395C5E070358A2 +57C28AA79B3BF2B747A330E2FDEC73F346CBD60DA71A4935728E724A27ED1BD5 +C349544A8B5BD31C3AE9B6A9DEE98A0DD5783639CB0F6E6690888E1C4B7E2092 +AB0DE200E57FDEDBDCF9E98843A94BA7FB261E097894B95BE80D03DC6AD422FE +25D92302F39B7ED78522B339D8950B758F096CF1CE01100D5C33F72F6DAE1425 +5706786C20894F832EEDB26A9058940184638D4F3F3EAF9D167C829AFC82E310 +D35F581577D1498B88D9642DD82F572AE4906D81B130E4F0F3286F6CDBE67320 +6E96791D05619938D358EAAE0B59397B2DD87B2279FDE6FB05B5D1D68115D9B3 +3FEF948E1292E9553F5C856D4FF6948F158E244EAA6808782A0BBECDE7D0D7B7 +0B43539810320899786D9743CFA7583F3234194960FF5229B9BB2B747BC5DAE6 +7671D8A71EC3DFB3F0CFAFBEA76AF3382C35BBDE2DDC359DEC6317CE55EB73FA +3DD0FA9DBD94C5D84901141F94292C0F08582862E5602CDF98507CD6C4FDDF14 +D76A56CEF1ACAF336B6556018A8985AB4E48CF86EAEBAEA33B2C4E96BAE39EDB +53061A10D51BFA05B1936B2478FA04D9053ED8D3B1E88F55F363F74F7B2C4F34 +2643604BB48DD5BA126D39EA9DB5763BDD094B741C5362297D621ADA26C99DDA +91BBD641922C01ED31DB9E4A917553D291D54BDFB1E13019A6D3326F949ED9C9 +23E6702BE8E9B2156633566C211251F46A741CEE8B19C37FC53260A83FB2C39A +96A957284DB5D5E2DFC75C6252C7E40C560D2813A99116B4A532ED9627949F97 +613C109FA91936594FEB8977D4B7C40C50347545B625490EE21CC777135E772F +BB08F9B8538F14C4A0F9A9ABDCC0A0BB5DB6130B20DD2FAD74C43F4D3FD387A3 +7D94E29DBBDE3A7510BC296BD2BB5899E3801354D66338DEB7DC3283400E47D0 +61FD3428EF03F36F4422892D4C13701B2F2A7DF8F7BE090EF54F3A14A1C9BA50 +B49373045F704E3A2FC277E9059D9756D816A4B33C141334B3D458340412CB9B +C96086E681ECBF3EE0491D4ADB8B7FF3777AA8A502A04FF82A5F4DFF484902B1 +25A2B73B2FBA01FBF1D1F2AD5EFA88CE66E490149E41D2993933FD3778221D0A +6455FFA69B7EB0D72B68620DAD47F9BB2D93769645E60449BD295661DBA9D3AA +CDECF642BAA3A01EB895C43127DBBF4C0B3D4383EA415FE82584F08C34376494 +3EEBFFCEF6B07E6DC2609D18892D6D31A44ECB15166EC5FF01FD12066F136732 +9CEE55AE637C5B709DA27F00B2DA860045A14BF00C98A3034629F0BDB8ADACAB +1DEAD1CC85893544BAB61DF3582D75DD6030206809100BD1D36DC8F742549EC4 +C94B432F974DD085B60B9FF5304F700EA4071031138CF8ED9F9D570DCD8DBA71 +D6737EFF6F6A1D8425C8700580E402BE792E76A4959BA3ACF852D379FE6C788F +CAD9149D515178BAD197B7E7DC1C53A7A999AC2B9851425D7C07A04D1B73274C +42A80F0A16B9F5B91C04180BD34A8C5B33A1E7499BC70C4BCBA76EDD0608CE49 +A1C19CB666B4AABC8097EB08A86345783B2DE7376987C56259EE447EF10A4732 +BC2F2C133831273A23F23085B9232ED63A022B9A312B7E851D43C47AB249E132 +B73583A9C7D6B41ED3ACE394FA54214185EE97A5EB3472FA87AC53C6B8223DEA +C4A5D086066EC09E9E05E6D46EE9F84AD0175B316E520D840FB1A1172CAC6A17 +AEAEEE9A63EC81A0B8580C55866BE6A8543DA124C9828839686AD79FA4517116 +7B9F34B772890B6519772D520846EA247028F859C262F80A2A6F07B54F30BC87 +C8DBBD1C18EACC17C479FB48BB42D6208CB7B7009077EBBC4CDCEC3F39BBBDD7 +FD584A2AA0B2DCC8B65292774C7F5C0C77FF503B5E8B10EF5263FFDD06D6A91E +CCD5BDE548F4AEA0265411B25883EC8B720B18ED9430BB8319E355175979B428 +1ECA438F93BD2B9E2588D0D0ECF9DE3500BC5F5E395D6124799E5E9C76054253 +784B416E2C62D4093955DDFEDBB10048B9157F6D0D96503B36595295038CB4BA +03633999FD239D859EA487992FF28A199ACA0275B36D27A3ED33CC84BDC06E84 +03F3713DE11CB453A08F526F857F4A2AFDD3AD3F063D6CFE942C261D1DC83415 +031355C0F7663CB752D05EEF4D31F87B29F9144EFB29C2E99D9D92B290DE8F93 +F9C9008773540E04B234992EE9DA710A2297801B8E690F3F21B2958A4842007F +9EA92AD6AB2DE5BD6B8BEEFE739DEFEB345E5FFBCC9D1F9689FA8004DE6D2D7A +0504EADB42AFF43D061EB3AE68BC4F245A39A7FD0178CC44E401CF37D0E31942 +5BE8E81F0A0CB653C7CF6F3854B63675D2C2A1D6DC834DCA757398CFA1871050 +C2F2A290B966ED5A3E2582B83B6016DCFF34C1D6D574804808C3ADFA57FC1F06 +CA9211C33369CBC67A3BE7994B8297EF8683DB9EA40B20A30226E9B13877992F +0D8EBE451B03E63E48884409E67F48E40B625B13E5AED1D4D7377931DA14BE85 +3457164CCA843456405EF69DB4E89B889E5ACD70F8D754292A30B0076DDE0FAC +16FEBA9272EAAE9BB8F64B8424D73E41611B9EB91816146FDFA8EB1BC73731DD +DBAA08C8287EAFA0B9A918E2F6C6A37514674B0B01A7733B50740AFF18A62328 +385F1ACF603B7FC049F9B78A62EF63919F46CBE71F99433422DE4227E91A592A +79207BF5F7F09E18DF8DC3EDB7D322F24EEEE6307F11EAE07DC9CD0710907F29 +399E6D4BDFBAB769BA0DABE016F38C423551672C3E516E4E9B846BC18524DB13 +2F04D6E8D66E876160C33F497E9B016A62065003521E8E3C20A64FB64DAC93B4 +C6F79EBF0AFEB6553994E6F8D459206B3A06E59277229978F269BE38DEB189DE +637BA95E39908D19F873C769CB1F2487BD7ABD7B1A6DC506B7FF6B86F310BA02 + +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark +%%EndFont +TeXDict begin 39158280 55380996 1000 600 600 (ulogd.a4.dvi) +@start /Fa 133[39 39 39 1[39 39 39 39 39 39 39 39 39 +39 39 39 39 39 39 39 39 39 39 39 39 39 1[39 5[39 1[39 +1[39 39 1[39 1[39 39 39 1[39 39 3[39 39 39 39 39 39 39 +2[39 39 6[39 39 1[39 39 39 39 1[39 39 45[{}53 74.7198 +/CMTT9 rf /Fb 240[42 15[{}1 83.022 /CMSY10 rf /Fc 135[59 +2[62 44 44 46 1[62 56 62 93 31 59 1[31 62 56 34 51 62 +50 62 54 11[86 78 62 2[77 84 88 1[67 2[42 1[88 1[74 86 +81 1[85 12[56 56 56 56 1[56 31 37 32[62 12[{}41 99.6264 +/CMBX12 rf /Fd 132[48 42 50 50 1[50 53 37 38 39 50 53 +48 53 80 27 50 1[27 53 48 29 44 53 42 53 46 7[72 1[99 +72 73 66 53 72 72 65 72 75 91 57 2[36 1[75 60 63 73 69 +68 72 7[48 1[48 48 48 48 48 48 48 1[48 27 32 31[53 53 +56 11[{}60 83.022 /CMBX10 rf /Fe 137[71 75 52 53 55 1[75 +67 75 1[37 2[37 1[67 1[61 2[75 65 11[103 94 75 1[101 +1[101 105 128 81 2[50 1[106 1[88 103 97 1[102 11[67 67 +67 67 67 1[67 34[75 12[{}35 119.552 /CMBX12 rf /Ff 134[44 +2[44 44 44 44 44 44 44 44 1[44 44 44 1[44 1[44 1[44 44 +44 44 44 45[44 1[44 44 44 44 46[{}24 83.022 /CMTT10 rf +/Fg 134[38 38 2[43 30 32 28 1[43 42 43 66 20 41 1[20 +43 42 25 37 43 37 43 40 11[57 57 4[61 2[45 4[55 9[65 +8[42 1[42 3[23 1[23 2[32 32 27[45 12[{}34 83.022 /CMSS10 +rf /Fh 193[65 1[65 60[{}2 83.022 /CMMI10 rf /Fi 132[42 +37 44 44 60 44 46 32 33 33 44 46 42 46 69 23 44 25 23 +46 42 25 37 46 37 46 42 4[42 2[62 1[85 62 62 60 46 61 +65 57 65 62 76 52 65 43 30 62 65 54 57 63 60 59 62 65 +2[65 1[23 23 42 42 42 42 42 42 42 42 42 42 42 23 28 23 +65 1[32 32 23 2[42 1[42 23 18[69 46 46 48 11[{}81 83.022 +/CMR10 rf /Fj 139[58 62 55 1[83 81 83 128 3[38 83 81 +1[72 1[72 1[78 11[111 5[119 2[88 4[108 2[117 22[54 45[{}19 +172.188 /CMSS17 rf end +%%EndProlog +%%BeginSetup +%%Feature: *Resolution 600dpi +TeXDict begin +%%BeginPaperSize: a4 +a4 +%%EndPaperSize + end +%%EndSetup +%%Page: 1 1 +TeXDict begin 1 0 bop 0 0 a +SDict begin /product where{pop product(Distiller)search{pop pop pop +version(.)search{exch pop exch pop(3011)eq{gsave newpath 0 0 moveto +closepath clip/Courier findfont 10 scalefont setfont 72 72 moveto(.)show +grestore}if}{pop}ifelse}{pop}ifelse}if end + 0 0 a 0 0 a +SDict begin [ /Title () /Subject () /Creator (LaTeX with hyperref package) +/Author () /Producer (dvips + Distiller) /Keywords () /DOCINFO pdfmark +end + 0 0 a Black 0 +TeXcolorgray 0 -200 a +SDict begin H.S end + 0 -200 a 0 TeXcolorgray 0 TeXcolorgray +0 -200 a +SDict begin H.R end + 0 -200 a 0 -200 a +SDict begin [ /View [/XYZ H.V] /Dest (page.1) cvn H.B /DEST pdfmark +end + 0 -200 a Black Black 0 162 +a +SDict begin H.S end + 0 162 a 0 162 a +SDict begin H.R end + 0 162 a 0 162 a +SDict begin [ H.B pdfmark end + 0 162 a 28 162 a +SDict begin H.S end + 28 +162 a 28 162 a +SDict begin H.R end + 28 162 a 28 162 a +SDict begin [ H.B pdfmark end + 28 162 a 55 162 a +SDict begin H.S end + 55 +162 a 55 162 a +SDict begin H.R end + 55 162 a 55 162 a +SDict begin [ H.B pdfmark end + 55 162 a 83 162 a +SDict begin H.S end + 83 +162 a 83 162 a +SDict begin H.R end + 83 162 a 83 162 a +SDict begin [ H.B pdfmark end + 83 162 a 111 162 a +SDict begin H.S end + 111 +162 a 111 162 a +SDict begin H.R end + 111 162 a 111 162 a +SDict begin [ H.B pdfmark end + 111 162 a 0 162 a +SDict begin [ /Count -2 /Dest (section.1) cvn /Title (DESIGN) /OUT +pdfmark end + +0 162 a 0 162 a +SDict begin [ /Count -0 /Dest (subsection.1.1) cvn /Title (CONCEPT) +/OUT pdfmark end + 0 162 a 0 162 a +SDict begin [ /Count -0 /Dest (subsection.1.2) cvn /Title (DETAILS) +/OUT pdfmark end + 0 162 a 0 162 a +SDict begin [ /Count -3 /Dest (section.2) cvn /Title (INSTALLATION) +/OUT pdfmark end + 0 162 +a 0 162 a +SDict begin [ /Count -0 /Dest (subsection.2.1) cvn /Title (Linux kernel) +/OUT pdfmark end + 0 162 a 0 162 a +SDict begin [ /Count -0 /Dest (subsection.2.2) cvn /Title (ipt\137ULOG from netfilter/iptables patch-o-matic) +/OUT pdfmark end + 0 162 a 0 162 a +SDict begin [ /Count -2 /Dest (subsection.2.3) cvn /Title (ulogd) /OUT +pdfmark end + 0 162 a 0 162 +a +SDict begin [ /Count -0 /Dest (subsubsection.2.3.1) cvn /Title (Recompiling the source) +/OUT pdfmark end + 0 162 a 0 162 a +SDict begin [ /Count -0 /Dest (subsubsection.2.3.2) cvn /Title (Using a precompiled package) +/OUT pdfmark end + 0 162 a 0 162 a +SDict begin [ /Count -2 /Dest (section.3) cvn /Title (Configuration) +/OUT pdfmark end + 0 162 a 0 162 a +SDict begin [ /Count -3 /Dest (subsection.3.1) cvn /Title (iptables ULOG target) +/OUT pdfmark end + 0 162 +a 0 162 a +SDict begin [ /Count -0 /Dest (subsubsection.3.1.1) cvn /Title (Quick Setup) +/OUT pdfmark end + 0 162 a 0 162 a +SDict begin [ /Count -0 /Dest (subsubsection.3.1.2) cvn /Title (ULOG target reference) +/OUT pdfmark end + 0 162 a 0 162 a +SDict begin [ /Count -0 /Dest (subsubsection.3.1.3) cvn /Title (ipt\137ULOG module parameters) +/OUT pdfmark end + 0 162 a 0 162 +a +SDict begin [ /Count -2 /Dest (subsection.3.2) cvn /Title (ulogd) /OUT +pdfmark end + 0 162 a 0 162 a +SDict begin [ /Count -0 /Dest (subsubsection.3.2.1) cvn /Title (ulogd configfile syntax reference) +/OUT pdfmark end + 0 162 a 0 162 a +SDict begin [ /Count -0 /Dest (subsubsection.3.2.2) cvn /Title (ulogd commandline option reference) +/OUT pdfmark end + 0 162 a 0 162 a +SDict begin [ /Count -2 /Dest (section.4) cvn /Title (Available plugins) +/OUT pdfmark end + 0 162 +a 0 162 a +SDict begin [ /Count -3 /Dest (subsection.4.1) cvn /Title (Interpreter plugins) +/OUT pdfmark end + 0 162 a 0 162 a +SDict begin [ /Count -0 /Dest (subsubsection.4.1.1) cvn /Title (ulogd\137BASE.so) +/OUT pdfmark end + 0 162 a 0 162 a +SDict begin [ /Count -0 /Dest (subsubsection.4.1.2) cvn /Title (ulogd\137PWSNIFF.so) +/OUT pdfmark end + 0 162 a 0 162 +a +SDict begin [ /Count -0 /Dest (subsubsection.4.1.3) cvn /Title (ulogd\137LOCAL.so) +/OUT pdfmark end + 0 162 a 0 162 a +SDict begin [ /Count -7 /Dest (subsection.4.2) cvn /Title (Output plugins) +/OUT pdfmark end + 0 162 a 0 162 a +SDict begin [ /Count -0 /Dest (subsubsection.4.2.1) cvn /Title (ulogd\137OPRINT.so) +/OUT pdfmark end + 0 162 a 0 162 a +SDict begin [ /Count -0 /Dest (subsubsection.4.2.2) cvn /Title (ulogd\137LOGEMU.so) +/OUT pdfmark end + 0 162 +a 0 162 a +SDict begin [ /Count -0 /Dest (subsubsection.4.2.3) cvn /Title (ulogd\137MYSQL.so) +/OUT pdfmark end + 0 162 a 0 162 a +SDict begin [ /Count -0 /Dest (subsubsection.4.2.4) cvn /Title (ulogd\137PGSQL.so) +/OUT pdfmark end + 0 162 a 0 162 a +SDict begin [ /Count -0 /Dest (subsubsection.4.2.5) cvn /Title (ulogd\137PCAP.so) +/OUT pdfmark end + 0 162 a 0 162 +a +SDict begin [ /Count -0 /Dest (subsubsection.4.2.6) cvn /Title (ulogd\137SQLITE3.so) +/OUT pdfmark end + 0 162 a 0 162 a +SDict begin [ /Count -0 /Dest (subsubsection.4.2.7) cvn /Title (ulogd\137SYSLOG.so) +/OUT pdfmark end + 0 162 a 0 162 a +SDict begin [ /Count -0 /Dest (section.5) cvn /Title (QUESTIONS / COMMENTS) +/OUT pdfmark end + 0 162 a 0 162 a +SDict begin [ /Page 1 /View [ /Fit ] /PageMode /UseOutlines /DOCVIEW +pdfmark end + 0 162 +a 0 162 a +SDict begin [ {Catalog} << >> /PUT pdfmark end + 0 162 a 0 162 a +SDict begin H.S end + 0 162 a 0 162 a +SDict begin 13.68 H.A end + 0 162 a 0 162 +a +SDict begin [ /View [/XYZ H.V] /Dest (Doc-Start) cvn H.B /DEST pdfmark +end + 0 162 a 170 x Fj(ULOGD)53 b(-)h(the)h(Userspace)f(Logging)g(Daemon)p +0 446 3900 24 v 0 560 a Fi(Harald)27 b(W)-7 b(elte)28 +b Fh(<)p Fi(laforge@gn)n(umonks.org)p Fh(>)169 b Fi(Revision)27 +b($Revision:)36 b(5846)26 b($,)h($Date:)36 b(2005-07-12)24 +b(17:33:23)g(+0200)0 673 y(\(T)-7 b(ue,)28 b(12)f(Jul)g(2005\))f($)0 +979 y Fg(This)31 b(is)h(the)g(do)r(cumentation)f(fo)n(r)h +Ff(ulogd)p Fg(,)f(the)h(Userspace)g(logging)e(daemon.)50 +b(ulogd)31 b(mak)n(es)g(use)h(of)g(the)g(Linux)g Fh(>)p +Fg(=)g(2.4.x)0 1093 y(pack)n(et)27 b(\014lter)g(subsystem)g +(\(iptables\))g(and)h(the)f(ULOG)h(ta)n(rget)f(fo)n(r)h(iptables.)0 +1424 y Fe(Con)l(ten)l(ts)0 1506 y +SDict begin H.S end + 0 1506 a 0 1506 a +SDict begin 13.68 H.A end + 0 +1506 a 0 1506 a +SDict begin [ /View [/XYZ H.V] /Dest (section*.1) cvn H.B /DEST pdfmark +end + 0 1506 a 0 0 1 TeXcolorrgb 0 1663 a +SDict begin H.S end + 0 +1663 a Fd(1)77 b(DESIGN)500 1663 y +SDict begin 13.68 H.L end + 500 1663 a 500 1663 +a +SDict begin [ /Subtype /Link /Dest (section.1) cvn /H /I /Border [0 +0 0] /Color [1 0 0] H.B /ANN pdfmark end + 500 1663 a Black 3352 w Fd(1)p 0 0 1 TeXcolorrgb 125 +1820 a +SDict begin H.S end + 125 1820 a Fi(1.1)83 b(CONCEPT)736 1820 y +SDict begin 13.68 H.L end + 736 +1820 a 736 1820 a +SDict begin [ /Subtype /Link /Dest (subsection.1.1) cvn /H /I /Border +[0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 736 1820 a Black 60 w Fi(.)41 b(.)h(.)f(.)h(.)f(.)h +(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.) +f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h +(.)g(.)f(.)h(.)f(.)p Black 134 w(1)p Black 0 0 1 TeXcolorrgb +125 1976 a +SDict begin H.S end + 125 1976 a Fi(1.2)83 b(DET)-7 b(AILS)678 1976 +y +SDict begin 13.68 H.L end + 678 1976 a 678 1976 a +SDict begin [ /Subtype /Link /Dest (subsection.1.2) cvn /H /I /Border +[0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 678 1976 a Black 53 w Fi(.)42 +b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f +(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.) +g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)p Black 134 +w(2)p Black 0 0 1 TeXcolorrgb 0 2216 a +SDict begin H.S end + 0 2216 a Fd(2)77 +b(INST)-8 b(ALLA)g(TION)846 2216 y +SDict begin 13.68 H.L end + 846 2216 a 846 2216 +a +SDict begin [ /Subtype /Link /Dest (section.2) cvn /H /I /Border [0 +0 0] /Color [1 0 0] H.B /ANN pdfmark end + 846 2216 a Black 3006 w Fd(2)p 0 0 1 TeXcolorrgb 125 +2372 a +SDict begin H.S end + 125 2372 a Fi(2.1)83 b(Lin)n(ux)28 b(k)n(ernel)770 +2372 y +SDict begin 13.68 H.L end + 770 2372 a 770 2372 a +SDict begin [ /Subtype /Link /Dest (subsection.2.1) cvn /H /I /Border +[0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 770 2372 a Black 26 w Fi(.)41 +b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h +(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.) +f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)p Black 134 w(2)p +Black 0 0 1 TeXcolorrgb 125 2529 a +SDict begin H.S end + 125 2529 a Fi(2.2)83 +b(ipt)p 421 2529 25 4 v 31 w(ULOG)27 b(from)h(net\014lter/iptables)f +(patc)n(h-o-matic)2054 2529 y +SDict begin 13.68 H.L end + 2054 2529 a 2054 2529 a +SDict begin [ /Subtype /Link /Dest (subsection.2.2) cvn /H /I /Border +[0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + +2054 2529 a Black 33 w Fi(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.) +f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)p +Black 134 w(2)p Black 0 0 1 TeXcolorrgb 125 2685 a +SDict begin H.S end + 125 +2685 a Fi(2.3)83 b(ulogd)514 2685 y +SDict begin 13.68 H.L end + 514 2685 a 514 2685 +a +SDict begin [ /Subtype /Link /Dest (subsection.2.3) cvn /H /I /Border +[0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 514 2685 a Black 23 w Fi(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h +(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.) +f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h +(.)g(.)f(.)h(.)f(.)p Black 134 w(2)p Black 0 0 1 TeXcolorrgb +315 2842 a +SDict begin H.S end + 315 2842 a Fi(2.3.1)94 b(Recompiling)27 b(the)h(source)1428 +2842 y +SDict begin 13.68 H.L end + 1428 2842 a 1428 2842 a +SDict begin [ /Subtype /Link /Dest (subsubsection.2.3.1) cvn /H /I +/Border [0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 1428 2842 a Black 78 w +Fi(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h +(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.) +f(.)p Black 134 w(2)p Black 0 0 1 TeXcolorrgb 315 2998 +a +SDict begin H.S end + 315 2998 a Fi(2.3.2)94 b(Using)28 b(a)f(precompiled)g(pac)n(k)-5 +b(age)1633 2998 y +SDict begin 13.68 H.L end + 1633 2998 a 1633 2998 a +SDict begin [ /Subtype /Link /Dest (subsubsection.2.3.2) cvn /H /I +/Border [0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 1633 2998 a +Black 67 w Fi(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.) +g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f +(.)p Black 134 w(3)p Black 0 0 1 TeXcolorrgb 0 3238 a +SDict begin H.S end + +0 3238 a Fd(3)77 b(Con\014guration)699 3238 y +SDict begin 13.68 H.L end + 699 3238 +a 699 3238 a +SDict begin [ /Subtype /Link /Dest (section.3) cvn /H /I /Border [0 +0 0] /Color [1 0 0] H.B /ANN pdfmark end + 699 3238 a Black 3153 w Fd(3)p 0 0 1 TeXcolorrgb +125 3394 a +SDict begin H.S end + 125 3394 a Fi(3.1)83 b(iptables)28 b(ULOG)g(target)1115 +3394 y +SDict begin 13.68 H.L end + 1115 3394 a 1115 3394 a +SDict begin [ /Subtype /Link /Dest (subsection.3.1) cvn /H /I /Border +[0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 1115 3394 a Black 68 w +Fi(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f +(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.) +f(.)h(.)g(.)f(.)h(.)f(.)p Black 134 w(3)p Black 0 0 1 +TeXcolorrgb 315 3550 a +SDict begin H.S end + 315 3550 a Fi(3.1.1)94 b(Quic)n(k)27 +b(Setup)1028 3550 y +SDict begin 13.68 H.L end + 1028 3550 a 1028 3550 a +SDict begin [ /Subtype /Link /Dest (subsubsection.3.1.1) cvn /H /I +/Border [0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 1028 3550 +a Black 26 w Fi(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f +(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.) +g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)p Black 134 +w(3)p Black 0 0 1 TeXcolorrgb 315 3707 a +SDict begin H.S end + 315 3707 a Fi(3.1.2)94 +b(ULOG)28 b(target)e(reference)1419 3707 y +SDict begin 13.68 H.L end + 1419 3707 +a 1419 3707 a +SDict begin [ /Subtype /Link /Dest (subsubsection.3.1.2) cvn /H /I +/Border [0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 1419 3707 a Black 22 w Fi(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f +(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.) +g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)p Black 134 +w(3)p Black 0 0 1 TeXcolorrgb 315 3863 a +SDict begin H.S end + 315 3863 a Fi(3.1.3)94 +b(ipt)p 687 3863 25 4 v 31 w(ULOG)27 b(mo)r(dule)h(parameters)1681 +3863 y +SDict begin 13.68 H.L end + 1681 3863 a 1681 3863 a +SDict begin [ /Subtype /Link /Dest (subsubsection.3.1.3) cvn /H /I +/Border [0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 1681 3863 a Black 83 w +Fi(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f +(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)p +Black 134 w(4)p Black 0 0 1 TeXcolorrgb 125 4020 a +SDict begin H.S end + 125 +4020 a Fi(3.2)83 b(ulogd)514 4020 y +SDict begin 13.68 H.L end + 514 4020 a 514 4020 +a +SDict begin [ /Subtype /Link /Dest (subsection.3.2) cvn /H /I /Border +[0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 514 4020 a Black 23 w Fi(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h +(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.) +f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h +(.)g(.)f(.)h(.)f(.)p Black 134 w(4)p Black 0 0 1 TeXcolorrgb +315 4176 a +SDict begin H.S end + 315 4176 a Fi(3.2.1)94 b(ulogd)27 b(con\014g\014le)g(syn)n +(tax)g(reference)1741 4176 y +SDict begin 13.68 H.L end + 1741 4176 a 1741 4176 a +SDict begin [ /Subtype /Link /Dest (subsubsection.3.2.1) cvn /H /I +/Border [0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + +1741 4176 a Black 23 w Fi(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.) +f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f +(.)h(.)f(.)p Black 134 w(4)p Black 0 0 1 TeXcolorrgb +315 4333 a +SDict begin H.S end + 315 4333 a Fi(3.2.2)94 b(ulogd)27 b(commandline)h(option)f +(reference)1895 4333 y +SDict begin 13.68 H.L end + 1895 4333 a 1895 4333 a +SDict begin [ /Subtype /Link /Dest (subsubsection.3.2.2) cvn /H /I +/Border [0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 1895 4333 +a Black 63 w Fi(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f +(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)p +Black 134 w(5)p Black 0 0 1 TeXcolorrgb 0 4572 a +SDict begin H.S end + 0 4572 +a Fd(4)77 b(Av)-5 b(ailable)31 b(plugins)842 4572 y +SDict begin 13.68 H.L end + 842 +4572 a 842 4572 a +SDict begin [ /Subtype /Link /Dest (section.4) cvn /H /I /Border [0 +0 0] /Color [1 0 0] H.B /ANN pdfmark end + 842 4572 a Black 3010 w Fd(5)p 0 0 1 +TeXcolorrgb 125 4729 a +SDict begin H.S end + 125 4729 a Fi(4.1)83 b(In)n(terpreter)27 +b(plugins)995 4729 y +SDict begin 13.68 H.L end + 995 4729 a 995 4729 a +SDict begin [ /Subtype /Link /Dest (subsection.4.1) cvn /H /I /Border +[0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 995 4729 a +Black 59 w Fi(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.) +h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g +(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)p Black 134 +w(5)p Black 0 0 1 TeXcolorrgb 315 4885 a +SDict begin H.S end + 315 4885 a Fi(4.1.1)94 +b(ulogd)p 785 4885 25 4 v 29 w(BASE.so)1131 4885 y +SDict begin 13.68 H.L end + 1131 +4885 a 1131 4885 a +SDict begin [ /Subtype /Link /Dest (subsubsection.4.1.1) cvn /H /I +/Border [0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 1131 4885 a Black 52 w Fi(.)42 b(.)f(.)h(.)f(.)h(.)f +(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.) +h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)p +Black 134 w(5)p Black 0 0 1 TeXcolorrgb 315 5042 a +SDict begin H.S end + 315 +5042 a Fi(4.1.2)94 b(ulogd)p 785 5042 25 4 v 29 w(PWSNIFF.so)1295 +5042 y +SDict begin 13.68 H.L end + 1295 5042 a 1295 5042 a +SDict begin [ /Subtype /Link /Dest (subsubsection.4.1.2) cvn /H /I +/Border [0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 1295 5042 a Black 82 w +Fi(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h +(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.) +f(.)h(.)f(.)p Black 134 w(5)p Black 0 0 1 TeXcolorrgb +315 5198 a +SDict begin H.S end + 315 5198 a Fi(4.1.3)94 b(ulogd)p 785 5198 +25 4 v 29 w(LOCAL.so)1198 5198 y +SDict begin 13.68 H.L end + 1198 5198 a 1198 5198 +a +SDict begin [ /Subtype /Link /Dest (subsubsection.4.1.3) cvn /H /I +/Border [0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 1198 5198 a Black 50 w Fi(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f +(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.) +g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)p Black 134 +w(6)p Black 0 0 1 TeXcolorrgb 125 5355 a +SDict begin H.S end + 125 5355 a Fi(4.2)83 +b(Output)29 b(plugins)870 5355 y +SDict begin 13.68 H.L end + 870 5355 a 870 5355 +a +SDict begin [ /Subtype /Link /Dest (subsection.4.2) cvn /H /I /Border +[0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 870 5355 a Black 55 w Fi(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f +(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.) +h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)p +Black 134 w(6)p Black 0 0 1 TeXcolorrgb 315 5511 a +SDict begin H.S end + 315 +5511 a Fi(4.2.1)94 b(ulogd)p 785 5511 25 4 v 29 w(OPRINT.so)1242 +5511 y +SDict begin 13.68 H.L end + 1242 5511 a 1242 5511 a +SDict begin [ /Subtype /Link /Dest (subsubsection.4.2.1) cvn /H /I +/Border [0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 1242 5511 a Black 70 w +Fi(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f +(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.) +g(.)f(.)h(.)f(.)p Black 134 w(6)p Black 0 0 1 TeXcolorrgb +315 5668 a +SDict begin H.S end + 315 5668 a Fi(4.2.2)94 b(ulogd)p 785 5668 +25 4 v 29 w(LOGEMU.so)1284 5668 y +SDict begin 13.68 H.L end + 1284 5668 a 1284 5668 +a +SDict begin [ /Subtype /Link /Dest (subsubsection.4.2.2) cvn /H /I +/Border [0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 1284 5668 a Black 28 w Fi(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h +(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.) +f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)p Black 134 w(6)p +Black 0 0 1 TeXcolorrgb 315 5824 a +SDict begin H.S end + 315 5824 a Fi(4.2.3)94 +b(ulogd)p 785 5824 25 4 v 29 w(MYSQL.so)1208 5824 y +SDict begin 13.68 H.L end + 1208 +5824 a 1208 5824 a +SDict begin [ /Subtype /Link /Dest (subsubsection.4.2.3) cvn /H /I +/Border [0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 1208 5824 a Black 40 w Fi(.)41 b(.)h(.)f(.)h(.)f(.)h +(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.) +f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)p +Black 134 w(6)p Black 0 0 1 TeXcolorrgb 315 5981 a +SDict begin H.S end + 315 +5981 a Fi(4.2.4)94 b(ulogd)p 785 5981 25 4 v 29 w(PGSQL.so)1192 +5981 y +SDict begin 13.68 H.L end + 1192 5981 a 1192 5981 a +SDict begin [ /Subtype /Link /Dest (subsubsection.4.2.4) cvn /H /I +/Border [0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 1192 5981 a Black 56 w +Fi(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h +(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.) +h(.)g(.)f(.)h(.)f(.)p Black 134 w(7)p Black 0 0 1 TeXcolorrgb +315 6137 a +SDict begin H.S end + 315 6137 a Fi(4.2.5)94 b(ulogd)p 785 6137 +25 4 v 29 w(PCAP)-7 b(.so)1136 6137 y +SDict begin 13.68 H.L end + 1136 6137 a 1136 +6137 a +SDict begin [ /Subtype /Link /Dest (subsubsection.4.2.5) cvn /H /I +/Border [0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 1136 6137 a Black 47 w Fi(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f +(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.) +f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)p +Black 134 w(8)p Black 0 0 1 TeXcolorrgb 315 6293 a +SDict begin H.S end + 315 +6293 a Fi(4.2.6)94 b(ulogd)p 785 6293 25 4 v 29 w(SQLITE3.so)1259 +6293 y +SDict begin 13.68 H.L end + 1259 6293 a 1259 6293 a +SDict begin [ /Subtype /Link /Dest (subsubsection.4.2.6) cvn /H /I +/Border [0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 1259 6293 a Black 53 w +Fi(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f +(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.) +g(.)f(.)h(.)f(.)p Black 134 w(8)p Black 0 0 1 TeXcolorrgb +315 6450 a +SDict begin H.S end + 315 6450 a Fi(4.2.7)94 b(ulogd)p 785 6450 +25 4 v 29 w(SYSLOG.so)1243 6450 y +SDict begin 13.68 H.L end + 1243 6450 a 1243 6450 +a +SDict begin [ /Subtype /Link /Dest (subsubsection.4.2.7) cvn /H /I +/Border [0 0 0] /Color [1 0 0] H.B /ANN pdfmark end + 1243 6450 a Black 69 w Fi(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h +(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.) +f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)p Black 134 w(8)p +Black 0 0 1 TeXcolorrgb 0 6689 a +SDict begin H.S end + 0 6689 a Fd(5)77 b(QUESTIONS)31 +b(/)h(COMMENTS)1379 6689 y +SDict begin 13.68 H.L end + 1379 6689 a 1379 6689 a +SDict begin [ /Subtype /Link /Dest (section.5) cvn /H /I /Border [0 +0 0] /Color [1 0 0] H.B /ANN pdfmark end + 1379 +6689 a Black 2473 w Fd(9)0 6828 y +SDict begin H.S end + 0 6828 a 0 6828 a +SDict begin 13.68 H.A end + 0 +6828 a 0 6828 a +SDict begin [ /View [/XYZ H.V] /Dest (section.1) cvn H.B /DEST pdfmark +end + 0 6828 a 193 x Fe(1)135 b(DESIGN)0 7103 +y +SDict begin H.S end + 0 7103 a 0 7103 a +SDict begin 13.68 H.A end + 0 7103 a 0 7103 a +SDict begin [ /View [/XYZ H.V] /Dest (subsection.1.1) cvn H.B /DEST +pdfmark end + 0 7103 a 175 x +Fc(1.1)112 b(CONCEPT)0 7488 y Fi(I)40 b(w)n(an)n(t)f(to)g(pro)n(vide)g +(a)g(\015exible,)j(almost)d(univ)n(ersal)g(logging)f(daemon)h(for)g(m)n +(y)g(net\014lter)h(ULOG)g(target.)72 b(It)40 b(is)f(not)0 +7602 y(optimized)e(in)g(an)n(y)f(w)n(a)n(y)-7 b(,)37 +b(the)h(goal)d(is)h(to)h(k)n(eep)f(as)g(simple)h(as)f(p)r(ossible.)64 +b(These)36 b(are)g(m)n(y)g(though)n(ts)g(ab)r(out)h(ho)n(w)f(the)0 +7715 y(arc)n(hitecture)26 b(whic)n(h)i(is)f(most)h(capable)f(of)g +(doing)g(that:)p Black 0 7913 a Fd(In)m(terpreter)33 +b(plugins)p Black 208 8052 a Fi(It)40 b(should)f(b)r(e)i(p)r(ossible)e +(to)h(add)g(plugins)f(/)h(run)n(time)g(mo)r(dules)f(for)h(new)g(proto)r +(cols,)h(etc.)74 b(F)-7 b(or)39 b(example)h(the)208 8165 +y(standard)30 b(logging)f(daemon)h(pro)n(vides)g(source-ip,)g(dest-ip,) +i(source-p)r(ort,)e(dest-p)r(ort,)i(etc.)47 b(Logging)29 +b(for)h(v)-5 b(arious)208 8279 y(other)27 b(proto)r(cols)f(\(GRE,)i +(IPsec,)e(...\))38 b(ma)n(y)27 b(b)r(e)h(implemen)n(ted)g(as)f(mo)r +(dules.)p Black Black eop end +%%Page: 2 2 +TeXDict begin 2 1 bop 0 0 a +SDict begin /product where{pop product(Distiller)search{pop pop pop +version(.)search{exch pop exch pop(3011)eq{gsave newpath 0 0 moveto +closepath clip/Courier findfont 10 scalefont setfont 72 72 moveto(.)show +grestore}if}{pop}ifelse}{pop}ifelse}if end + 0 0 a Black 0 TeXcolorgray +0 -200 a +SDict begin H.S end + 0 -200 a 0 TeXcolorgray 0 TeXcolorgray 0 -200 +a +SDict begin H.R end + 0 -200 a 0 -200 a +SDict begin [ /View [/XYZ H.V] /Dest (page.2) cvn H.B /DEST pdfmark +end + 0 -200 a Black 0 -167 3900 5 v Fd(2.)74 +b(INST)-8 b(ALLA)g(TION)2988 b Fi(2)p Black Black 0 162 +a Fd(Output)32 b(plugins)p Black 208 308 a Fi(...)51 +b(describ)r(e)32 b(ho)n(w)g(and)g(where)g(to)g(put)h(the)g(information) +f(gained)g(b)n(y)g(logging)e(plugins.)52 b(The)32 b(easiest)g(w)n(a)n +(y)f(is)h(to)208 422 y(build)d(a)g(line)g(p)r(er)g(pac)n(k)n(et)e(and)i +(fprin)n(t)g(it)h(to)e(a)h(\014le.)41 b(Some)29 b(p)r(eople)g(migh)n(t) +f(w)n(an)n(t)h(to)f(log)h(in)n(to)f(a)h(SQL)f(database)g(or)208 +536 y(w)n(an)n(t)e(an)i(output)g(conforming)e(to)i(the)g(in)n(trusion)f +(detection)h(systems)f(comm)n(unication)g(draft)g(from)g(the)h(IETF.)0 +668 y +SDict begin H.S end + 0 668 a 0 668 a +SDict begin 13.68 H.A end + 0 668 a 0 668 a +SDict begin [ /View [/XYZ H.V] /Dest (subsection.1.2) cvn H.B /DEST +pdfmark end + 0 668 a 159 x Fc(1.2)112 +b(DET)-9 b(AILS)0 1037 y Fi(The)39 b(ma)5 b(jor)37 b(clue)i(is)f(pro)n +(viding)f(a)i(framew)n(ork)d(whic)n(h)j(is)f(as)g(\015exible)h(as)f(p)r +(ossible.)70 b(Nob)r(o)r(dy)38 b(kno)n(ws)g(what)g(strange)0 +1151 y(net)n(w)n(ork)d(proto)r(cols)f(are)h(out)h(there)g(:\))53 +b(Flexibilit)n(y)37 b(dep)r(ends)f(on)g(the)g(comm)n(unication)f(b)r +(et)n(w)n(een)h(the)g(output)h(of)f(the)0 1264 y(logging)26 +b(plugins)h(and)h(input)g(of)g(the)g(output)g(plugins.)0 +1421 y(Rust)n(y)f(advised)g(me)h(to)g(use)f(some)g(kind)h(of)f(t)n(yp)r +(e-k)n(ey-v)-5 b(alue)27 b(triples,)g(whic)n(h)h(is)f(in)h(fact)g(what) +f(I)h(implemen)n(ted.)0 1577 y(One)h(issue)h(is,)g(of)f(course,)g(p)r +(erformance.)42 b(Up)30 b(to)g(ulogd)f(0.3,)g(ulogd)g(did)h(sev)n(eral) +e(link)n(ed)h(list)h(iterations)f(and)g(ab)r(out)h(30)0 +1691 y(mallo)r(c\(\))e(calls)p 520 1691 25 4 v 57 w(p)r(er)f(pac)n(k)n +(et)p 929 1691 V 29 w(.)37 b(This)27 b(c)n(hanged)g(with)h(the)g(new)g +Fh(>)p Fi(=)f(0.9)f(revisions:)p Black 125 1914 a Fb(\017)p +Black 41 w Fi(Not)34 b(a)g(single)g(dynamic)g(allo)r(cation)g(in)g(the) +h(core)f(during)f(run)n(time.)58 b(Ev)n(erything)33 b(is)h(pre-allo)r +(cated)f(at)h(start)g(of)208 2027 y(ulogd)27 b(to)g(pro)n(vide)f(the)i +(highest)g(p)r(ossible)f(throughput.)p Black 125 2207 +a Fb(\017)p Black 41 w Fi(Hash)i(tables)h(in)h(addition)f(to)g(the)g +(link)n(ed)h(lists.)44 b(Link)n(ed)30 b(lists)g(are)f(only)h(tra)n(v)n +(ersed)e(if)j(w)n(e)f(really)f(w)n(an)n(t)g(to)h(access)208 +2321 y(eac)n(h)c(elemen)n(t)i(of)g(the)g(list.)0 2446 +y +SDict begin H.S end + 0 2446 a 0 2446 a +SDict begin 13.68 H.A end + 0 2446 a 0 2446 a +SDict begin [ /View [/XYZ H.V] /Dest (section.2) cvn H.B /DEST pdfmark +end + 0 2446 a 213 x +Fe(2)135 b(INST)-11 b(ALLA)g(TION)0 2742 y +SDict begin H.S end + 0 2742 a 0 +2742 a +SDict begin 13.68 H.A end + 0 2742 a 0 2742 a +SDict begin [ /View [/XYZ H.V] /Dest (subsection.2.1) cvn H.B /DEST +pdfmark end + 0 2742 a 175 x Fc(2.1)112 b(Lin)m(ux)39 +b(k)m(ernel)0 3127 y Fi(First)c(y)n(ou)g(will)g(need)g(a)g(recen)n(t)g +(2.4.x)f(k)n(ernel.)59 b(If)36 b(y)n(ou)e(ha)n(v)n(e)g(a)h(k)n(ernel)g +Fh(>)p Fi(=)f(2.4.18-pre8,)g(it)i(already)e(has)g(the)i(k)n(ernel)0 +3241 y(supp)r(ort)27 b(for)g(ULOG)h(\(ipt)p 844 3241 +25 4 v 31 w(ULOG.o\).)0 3397 y(If)j(y)n(ou)g(ha)n(v)n(e)e(an)i(older)f +(k)n(ernel)g(v)n(ersion)g(\(b)r(et)n(w)n(een)h(2.4.0)f(and)h +(2.4.18-pre6\),)e(y)n(ou)h(can)h(use)f(the)i(patc)n(h-o-matic)d(system) +0 3511 y(of)f(net\014lter/iptables,)f(as)g(describ)r(ed)g(in)h(the)g +(follo)n(wing)e(section.)0 3648 y +SDict begin H.S end + 0 3648 a 0 3648 a +SDict begin 13.68 H.A end + 0 +3648 a 0 3648 a +SDict begin [ /View [/XYZ H.V] /Dest (subsection.2.2) cvn H.B /DEST +pdfmark end + 0 3648 a 154 x Fc(2.2)112 b(ipt)p 399 +3802 34 4 v 41 w(ULOG)38 b(from)g(net\014lter/iptables)g(patc)m +(h-o-matic)0 4012 y Fi(Y)-7 b(ou)28 b(only)f(need)h(to)f(read)g(this)h +(c)n(hapter)e(if)i(y)n(ou)f(ha)n(v)n(e)g(a)g(2.4.x)g(k)n(ernel)f +Fh(<)p Fi(=)h(2.4.18-pre6.)0 4169 y(In)h(order)f(to)h(put)h(the)f(ipt)p +826 4169 25 4 v 31 w(ULOG)g(mo)r(dule)g(in)n(to)g(y)n(our)f(k)n(ernel)g +(source,y)n(ou)g(need)h(the)g(latest)g(iptables)h(pac)n(k)-5 +b(age,)26 b(or)i(ev)n(en)0 4282 y(b)r(etter:)37 b(the)28 +b(latest)g(CVS)g(snapshot.)36 b(A)28 b(description)f(ho)n(w)g(to)g +(obtain)h(this)f(is)h(pro)n(vided)e(on)i(the)g(net\014lter)g(homepage) +81 b(.)0 4439 y(T)-7 b(o)27 b(run)h(patc)n(h-o-matic,)e(just)i(t)n(yp)r +(e)p Black Black Black Black 208 4652 a Fa(make)40 b(patch-o-matic)0 +4875 y Fi(in)28 b(the)g(userspace)e(directory)g(of)i(net\014lter)g +(CVS.)0 5007 y +SDict begin H.S end + 0 5007 a 0 5007 a +SDict begin 13.68 H.A end + 0 5007 a 0 5007 a +SDict begin [ /View [/XYZ H.V] /Dest (subsection.2.3) cvn H.B /DEST +pdfmark end + 0 +5007 a 160 x Fc(2.3)112 b(ulogd)0 5240 y +SDict begin H.S end + 0 5240 a 0 5240 +a +SDict begin 13.68 H.A end + 0 5240 a 0 5240 a +SDict begin [ /View [/XYZ H.V] /Dest (subsubsection.2.3.1) cvn H.B +/DEST pdfmark end + 0 5240 a 137 x Fd(2.3.1)94 b(Recompiling)29 +b(the)j(source)0 5587 y Fi(Do)n(wnload)27 b(the)h(ulogd)f(pac)n(k)-5 +b(age)26 b(from)82 b(and)28 b(un)n(tar)f(it.)p Black +Black eop end +%%Page: 3 3 +TeXDict begin 3 2 bop 0 0 a +SDict begin /product where{pop product(Distiller)search{pop pop pop +version(.)search{exch pop exch pop(3011)eq{gsave newpath 0 0 moveto +closepath clip/Courier findfont 10 scalefont setfont 72 72 moveto(.)show +grestore}if}{pop}ifelse}{pop}ifelse}if end + 0 0 a Black 0 TeXcolorgray +0 -200 a +SDict begin H.S end + 0 -200 a 0 TeXcolorgray 0 TeXcolorgray 0 -200 +a +SDict begin H.R end + 0 -200 a 0 -200 a +SDict begin [ /View [/XYZ H.V] /Dest (page.3) cvn H.B /DEST pdfmark +end + 0 -200 a Black 0 -167 3900 5 v Fd(3.)74 +b(Con\014guration)3135 b Fi(3)p Black 0 162 a(If)36 b(y)n(ou)f(w)n(an)n +(t)h(to)g(build)g(ulogd)f(with)i(MySQL)e(supp)r(ort,)j(t)n(yp)r(e)e +('./con\014gure)f({with-m)n(ysql'.)60 b(Y)-7 b(ou)36 +b(ma)n(y)g(also)e(ha)n(v)n(e)h(to)0 275 y(sp)r(ecify)29 +b(the)g(path)g(of)f(the)h(m)n(ysql)f(libraries)f(using)i('{with-m)n +(ysql=path'.)38 b(T)-7 b(o)29 b(build)g(ulogd)f(without)h(MySQL)f(supp) +r(ort,)0 389 y(just)g(use)g('./con\014gure'.)0 545 y(T)-7 +b(o)27 b(compile)h(and)f(install)h(the)g(program,)d(call)i('mak)n(e)g +(install'.)0 673 y +SDict begin H.S end + 0 673 a 0 673 a +SDict begin 13.68 H.A end + 0 673 a 0 673 a +SDict begin [ /View [/XYZ H.V] /Dest (subsubsection.2.3.2) cvn H.B +/DEST pdfmark end + 0 +673 a 140 x Fd(2.3.2)94 b(Using)31 b(a)h(precompiled)f(pac)m(k)-5 +b(age)0 1023 y Fi(I)28 b(also)e(pro)n(vide)h(a)g(SRPM,)g(whic)n(h)h +(should)f(compile)h(on)f(almost)g(an)n(y)g(rpm-based)f(distribution.)37 +b(It)28 b(is)g(a)n(v)-5 b(ailable)26 b(at)0 1180 y(Just)h(do)n(wnload)g +(the)h(pac)n(k)-5 b(age)26 b(and)h(do)h(the)g(usual)f('rpm)g({rebuild)g +Fh(<)p Fi(\014le)p Fh(>)p Fi('.)0 1317 y +SDict begin H.S end + 0 1317 a 0 1317 +a +SDict begin 13.68 H.A end + 0 1317 a 0 1317 a +SDict begin [ /View [/XYZ H.V] /Dest (section.3) cvn H.B /DEST pdfmark +end + 0 1317 a 197 x Fe(3)135 b(Con\014guration)0 +1619 y +SDict begin H.S end + 0 1619 a 0 1619 a +SDict begin 13.68 H.A end + 0 1619 a 0 1619 a +SDict begin [ /View [/XYZ H.V] /Dest (subsection.3.1) cvn H.B /DEST +pdfmark end + 0 1619 a 152 +x Fc(3.1)112 b(iptables)39 b(ULOG)f(target)0 1844 y +SDict begin H.S end + 0 +1844 a 0 1844 a +SDict begin 13.68 H.A end + 0 1844 a 0 1844 a +SDict begin [ /View [/XYZ H.V] /Dest (subsubsection.3.1.1) cvn H.B +/DEST pdfmark end + 0 1844 a 137 x Fd(3.1.1)94 +b(Quic)m(k)32 b(Setup)0 2191 y Fi(Just)27 b(add)h(rules)f(using)g(the)h +(ULOG)g(target)e(to)i(y)n(our)e(\014rew)n(alling)g(c)n(hain.)37 +b(A)28 b(v)n(ery)e(basic)h(example:)p Black Black Black +Black 208 2383 a Fa(iptables)41 b(-A)e(FORWARD)i(-j)f(ULOG)g +(--ulog-nlgroup)i(32)e(--ulog-prefix)i(foo)0 2585 y Fi(T)-7 +b(o)27 b(increase)g(logging)f(p)r(erformance,)g(try)h(to)h(use)f(the)p +Black Black Black Black 208 2777 a Fa(--ulog-qthreshold)43 +b(N)0 2978 y Fi(option)32 b(\(where)h(1)f Fh(<)g Fi(N)h +Fh(<)p Fi(=)f(50\).)51 b(The)32 b(n)n(um)n(b)r(er)h(y)n(ou)f(sp)r +(ecify)g(is)h(the)g(amoun)n(t)f(of)g(pac)n(k)n(ets)g(batc)n(hed)g +(together)g(in)g(one)0 3092 y(m)n(ultipart)c(netlink)h(message.)38 +b(If)29 b(y)n(ou)f(set)g(this)h(to)g(20,)e(the)i(k)n(ernel)f(sc)n +(hedules)g(ulogd)g(only)g(once)g(ev)n(ery)f(20)g(pac)n(k)n(ets.)39 +b(All)0 3205 y(20)31 b(pac)n(k)n(ets)g(are)f(then)j(pro)r(cessed)d(b)n +(y)i(ulogd.)49 b(This)32 b(reduces)f(the)h(n)n(um)n(b)r(er)g(of)g(con)n +(text)f(switc)n(hes)g(b)r(et)n(w)n(een)h(k)n(ernel)f(and)0 +3319 y(userspace.)0 3475 y(Of)24 b(course)f(y)n(ou)g(can)g(com)n(bine)h +(the)g(ULOG)g(target)f(with)h(the)h(di\013eren)n(t)f(net\014lter)g +(matc)n(h)f(mo)r(dules.)36 b(F)-7 b(or)23 b(a)h(more)f(detailed)0 +3589 y(description,)k(ha)n(v)n(e)g(a)g(lo)r(ok)g(at)g(the)h +(net\014lter)g(HO)n(WTO's,)f(a)n(v)-5 b(ailable)26 b(on)h(the)h +(net\014lter)g(homepage.)0 3717 y +SDict begin H.S end + 0 3717 a 0 3717 a +SDict begin 13.68 H.A end + 0 +3717 a 0 3717 a +SDict begin [ /View [/XYZ H.V] /Dest (subsubsection.3.1.2) cvn H.B +/DEST pdfmark end + 0 3717 a 140 x Fd(3.1.2)94 b(ULOG)32 +b(target)h(reference)p Black 0 4052 a({ulog-nlgroup)d(N)p +Black 208 4193 a Fi(The)e(n)n(um)n(b)r(er)g(of)g(the)h(netlink)g(m)n +(ulticast)f(group)f(to)i(whic)n(h)f(ULOG'ed)g(pac)n(k)n(ets)f(are)h +(sen)n(t.)39 b(Y)-7 b(ou)28 b(will)h(ha)n(v)n(e)e(to)h(use)208 +4307 y(the)g(same)f(group)f(n)n(um)n(b)r(er)h(in)h(the)g(ULOG)g(target) +e(and)i(ulogd)f(in)h(order)e(to)h(mak)n(e)g(logging)f(w)n(ork.)p +Black 0 4476 a Fd({ulog-cprange)31 b(N)p Black 208 4618 +a Fi(Cop)n(yrange.)42 b(This)30 b(w)n(orks)e(lik)n(e)i(the)g('snaplen') +g(parameter)f(of)h(tcp)r(dump.)46 b(Y)-7 b(ou)30 b(can)f(sp)r(ecify)i +(a)f(n)n(um)n(b)r(er)f(of)h(b)n(ytes)208 4731 y(up)25 +b(to)h(whic)n(h)f(the)h(pac)n(k)n(et)e(is)h(copied.)36 +b(If)26 b(y)n(ou)f(sa)n(y)f('40',)h(y)n(ou)g(will)g(receiv)n(e)g(the)g +(\014rst)h(fourt)n(y)e(b)n(ytes)i(of)f(ev)n(ery)f(pac)n(k)n(et.)208 +4845 y(Lea)n(v)n(e)i(it)i(to)f Ff(0)p Black 0 5014 a +Fd({ulog-qthreshold)j(N)p Black 208 5155 a Fi(Queue)d(threshold.)36 +b(If)28 b(a)f(pac)n(k)n(et)g(is)g(matc)n(hed)h(b)n(y)f(the)h(iptables)g +(rule,)f(and)g(already)f(N)i(pac)n(k)n(ets)f(are)f(in)i(the)g(queue,) +208 5269 y(the)34 b(queue)f(is)h(\015ushed)g(to)f(userspace.)54 +b(Y)-7 b(ou)33 b(can)h(use)f(this)h(to)f(implemen)n(t)i(a)e(p)r(olicy)g +(lik)n(e:)49 b(Use)34 b(a)f(big)g(queue)h(in)208 5383 +y(order)26 b(to)h(gain)g(high)h(p)r(erformance,)e(but)i(still)g(ha)n(v) +n(e)f(certain)g(pac)n(k)n(ets)f(logged)g(immediately)i(to)g(userspace.) +p Black 0 5552 a Fd({ulog-pre\014x)j(STRING)p Black 208 +5693 a Fi(A)d(string)f(that)h(is)g(asso)r(ciated)f(with)h(ev)n(ery)f +(pac)n(k)n(et)g(logged)g(b)n(y)g(this)i(rule.)37 b(Y)-7 +b(ou)28 b(can)g(use)g(this)g(option)g(to)f(later)h(tell)208 +5807 y(from)f(whic)n(h)g(rule)h(the)g(pac)n(k)n(et)e(w)n(as)h(logged.)p +Black Black eop end +%%Page: 4 4 +TeXDict begin 4 3 bop 0 0 a +SDict begin /product where{pop product(Distiller)search{pop pop pop +version(.)search{exch pop exch pop(3011)eq{gsave newpath 0 0 moveto +closepath clip/Courier findfont 10 scalefont setfont 72 72 moveto(.)show +grestore}if}{pop}ifelse}{pop}ifelse}if end + 0 0 a Black 0 TeXcolorgray +0 -200 a +SDict begin H.S end + 0 -200 a 0 TeXcolorgray 0 TeXcolorgray 0 -200 +a +SDict begin H.R end + 0 -200 a 0 -200 a +SDict begin [ /View [/XYZ H.V] /Dest (page.4) cvn H.B /DEST pdfmark +end + 0 -200 a Black 0 -167 3900 5 v Fd(3.)74 +b(Con\014guration)3135 b Fi(4)p Black 0 79 a +SDict begin H.S end + 0 79 a 0 +79 a +SDict begin 13.68 H.A end + 0 79 a 0 79 a +SDict begin [ /View [/XYZ H.V] /Dest (subsubsection.3.1.3) cvn H.B +/DEST pdfmark end + 0 79 a 83 x Fd(3.1.3)94 b(ipt)p 415 +162 29 4 v 34 w(ULOG)32 b(mo)s(dule)e(parameters)0 372 +y Fi(The)25 b(ipt)p 274 372 25 4 v 30 w(ULOG)g(k)n(ernel)f(mo)r(dule)h +(has)f(a)h(couple)f(of)h(mo)r(dule)g(loadtime)f(parameters)f(whic)n(h)i +(can)g(\(and)f(should\))h(b)r(e)g(tuned)0 485 y(to)i(accomo)r(date)g +(the)h(needs)f(of)h(the)g(application:)p Black 0 708 +a Fd(nlbufsiz)j(N)p Black 208 855 a Fi(Netlink)h(bu\013er)f(size.)48 +b(A)32 b(bu\013er)g(of)f(the)h(sp)r(eci\014ed)g(size)f(N)h(is)f(allo)r +(cated)g(for)g(ev)n(ery)f(netlink)i(group)e(that)i(is)f(used.)208 +969 y(Please)h(note)h(that)h(due)f(to)g(restrictions)g(of)g(the)h(k)n +(ernel)e(memory)h(allo)r(cator,)g(w)n(e)g(cannot)g(ha)n(v)n(e)f(a)h +(bu\013er)g(size)g Fh(>)208 1082 y Fi(128kBytes.)42 b(Larger)28 +b(bu\013er)i(sizes)f(increase)g(the)i(p)r(erformance,)e(since)h(less)g +(k)n(ernel/userspace)d(con)n(text)j(switc)n(hes)208 1196 +y(are)j(needed)h(for)g(the)g(same)g(amoun)n(t)g(of)g(pac)n(k)n(ets.)56 +b(The)34 b(bac)n(kside)f(of)h(this)h(p)r(erformance)e(gain)g(is)h(a)g +(p)r(oten)n(tially)208 1309 y(larger)25 b(dela)n(y)-7 +b(.)36 b(The)28 b(default)g(v)-5 b(alue)28 b(is)f(4096)f(b)n(ytes,)h +(whic)n(h)h(is)f(quite)h(small.)p Black 0 1489 a Fd(\015ush)m(timeout)j +(N)p Black 208 1636 a Fi(The)38 b(\015ush)n(timeout)h(determines,)h +(after)e(ho)n(w)g(man)n(y)g(clo)r(c)n(k)f(tic)n(ks)h(\(on)h(alpha:)57 +b(1ms,)41 b(on)d(x86)f(and)i(most)f(other)208 1750 y(platforms:)h(10ms) +29 b(time)g(units\))h(the)g(bu\013er/queue)f(is)g(to)g(b)r(e)h +(\015ushed,)g(ev)n(en)f(if)g(it)h(is)f(not)h(full.)42 +b(This)30 b(can)e(b)r(e)i(used)208 1863 y(to)24 b(ha)n(v)n(e)g(the)h +(adv)-5 b(an)n(tage)23 b(of)h(a)h(large)e(bu\013er,)i(but)h(still)f(a)f +(\014nite)h(maxim)n(um)g(dela)n(y)f(in)n(tro)r(duced.)35 +b(The)25 b(default)g(v)-5 b(alue)208 1977 y(is)27 b(set)h(to)f(10)g +(seconds.)0 2200 y(Example:)p Black Black Black Black +208 2413 a Fa(modprobe)41 b(ipt_ULOG)g(nlbufsiz=65535)h +(flushtimeout=100)0 2636 y Fi(This)28 b(w)n(ould)f(use)g(a)g(bu\013er)h +(size)f(of)h(64k)e(and)i(a)f(\015ush)n(timeout)h(of)f(100)g(clo)r(c)n +(ktic)n(ks)f(\(1)i(second)e(on)i(x86\).)0 2773 y +SDict begin H.S end + 0 2773 +a 0 2773 a +SDict begin 13.68 H.A end + 0 2773 a 0 2773 a +SDict begin [ /View [/XYZ H.V] /Dest (subsection.3.2) cvn H.B /DEST +pdfmark end + 0 2773 a 155 x Fc(3.2)112 +b(ulogd)0 3138 y Fi(ulogd)27 b(is)g(what)h(this)g(is)f(all)h(ab)r(out,) +f(so)g(let's)h(describ)r(e)f(it's)h(con\014guration...)0 +3270 y +SDict begin H.S end + 0 3270 a 0 3270 a +SDict begin 13.68 H.A end + 0 3270 a 0 3270 a +SDict begin [ /View [/XYZ H.V] /Dest (subsubsection.3.2.1) cvn H.B +/DEST pdfmark end + 0 3270 a 140 +x Fd(3.2.1)94 b(ulogd)31 b(con\014g\014le)g(syn)m(tax)i(reference)0 +3620 y Fi(All)28 b(con\014gurable)e(parameters)g(of)i(ulogd)f(are)f(in) +i(the)g(con\014g\014le,)f(t)n(ypically)g(lo)r(cated)g(at)h +('/etc/ulogd.conf)6 b('.)0 3777 y(The)28 b(follo)n(wing)e +(con\014guration)g(parameters)g(are)h(a)n(v)-5 b(ailable:)p +Black 0 4000 a Fd(nlgroup)p Black 208 4147 a Fi(The)28 +b(netlink)g(m)n(ulticast)h(group,)e(whic)n(h)h(ulgogd)f(should)h(bind)h +(to.)38 b(This)28 b(is)g(the)h(same)e(as)h(giv)n(en)f(with)i(the)g +('{ulog-)208 4260 y(nlgroup')d(option)i(to)f(iptables.)p +Black 0 4440 a Fd(log\014le)p Black 208 4587 a Fi(The)32 +b(main)g(log\014le,)h(where)f(ulogd)g(rep)r(orts)f(an)n(y)h(errors,)g +(w)n(arnings)e(and)j(other)e(unexp)r(ected)i(conditions.)51 +b(Apart)208 4700 y(from)24 b(a)h(regular)e(\014lename,)i(the)h(follo)n +(wing)e(sp)r(ecial)g(v)-5 b(alues)25 b(can)g(b)r(e)g(used;)h(\\syslog") +c(to)j(log)f(via)h(the)g(unix)h(syslog\(3\))208 4814 +y(mec)n(hanism.)36 b(\\stdout")27 b(to)g(log)g(to)g(stdout.)p +Black 0 4994 a Fd(loglev)m(el)p Black 208 5141 a Fi(This)32 +b(sp)r(eci\014es,)j(ho)n(w)d(v)n(erb)r(ose)f(the)i(logging)f(to)g +(log\014le)h(is.)52 b(Curren)n(tly)32 b(de\014ned)h(loglev)n(els)f +(are:)46 b(1=debug)32 b(infor-)208 5254 y(mation,)37 +b(3=informational)d(messages,)j(5=noticable)e(exceptional)g +(conditions,)i(7=error)d(conditions,)j(8=fatal)208 5368 +y(errors,)25 b(program)h(ab)r(ort.)p Black 0 5548 a Fd(plugin)p +Black 208 5695 a Fi(This)34 b(option)g(is)h(follo)n(w)n(ed)e(b)n(y)h(a) +g(\014lename)h(of)f(a)g(ulogd)g(plugin,)i(whic)n(h)f(ulogd)f(shold)g +(load)g(up)r(on)g(initialization.)208 5808 y(This)27 +b(option)g(ma)n(y)g(app)r(ear)g(more)g(than)g(once.)p +Black Black eop end +%%Page: 5 5 +TeXDict begin 5 4 bop 0 0 a +SDict begin /product where{pop product(Distiller)search{pop pop pop +version(.)search{exch pop exch pop(3011)eq{gsave newpath 0 0 moveto +closepath clip/Courier findfont 10 scalefont setfont 72 72 moveto(.)show +grestore}if}{pop}ifelse}{pop}ifelse}if end + 0 0 a Black 0 TeXcolorgray +0 -200 a +SDict begin H.S end + 0 -200 a 0 TeXcolorgray 0 TeXcolorgray 0 -200 +a +SDict begin H.R end + 0 -200 a 0 -200 a +SDict begin [ /View [/XYZ H.V] /Dest (page.5) cvn H.B /DEST pdfmark +end + 0 -200 a Black 0 -167 3900 5 v Fd(4.)74 +b(Av)-5 b(ailable)31 b(plugins)2992 b Fi(5)p Black Black +0 162 a Fd(rmem)p Black 208 308 a Fi(Size)40 b(of)h(the)g(netlink)g(so) +r(c)n(k)n(et)e(receiv)n(e)h(memory)-7 b(.)75 b(Y)-7 b(ou)40 +b(should)h(set)f(this)h(to)g(at)f(least)g(the)h(size)f(of)h(the)g(k)n +(ernel)208 422 y(bu\013er)32 b(\(nlbufsiz)h(parameter)e(of)h(the)h(ipt) +p 1549 422 25 4 v 30 w(ULOG)g(mo)r(dule\).)51 b(Please)31 +b(note)i(that)f(there)g(is)h(a)f(maxim)n(um)g(limit)h(in)208 +536 y(/pro)r(c/sys/net/core/rmem)p 1165 536 V 25 w(max)f(whic)n(h)h(y)n +(ou)f(cannot)h(exceed)f(b)n(y)h(increasing)e(the)j(\\rmem")e +(parameter.)51 b(Y)-7 b(ou)208 649 y(ma)n(y)26 b(need)i(to)g(raise)e +(the)i(system-wide)f(maxim)n(um)h(limit)g(b)r(efore.)p +Black 0 829 a Fd(bufsize)p Black 208 976 a Fi(Size)f(of)h(the)g(receiv) +n(e)e(bu\013er.)37 b(Y)-7 b(ou)28 b(should)f(set)h(this)g(to)f(at)h +(least)f(the)h(so)r(c)n(k)n(et)e(receiv)n(e)h(bu\013er)g(\(rmem\).)0 +1113 y +SDict begin H.S end + 0 1113 a 0 1113 a +SDict begin 13.68 H.A end + 0 1113 a 0 1113 a +SDict begin [ /View [/XYZ H.V] /Dest (subsubsection.3.2.2) cvn H.B +/DEST pdfmark end + 0 1113 a 136 +x Fd(3.2.2)94 b(ulogd)31 b(commandline)f(option)h(reference)0 +1459 y Fi(Apart)c(from)h(the)g(con\014g\014le,)f(there)g(are)g(a)g +(couple)g(of)h(commandline)f(options)g(to)h(ulogd:)p +Black 0 1682 a Fd(-h)k({help)p Black 208 1828 a Fi(Prin)n(t)26 +b(a)i(help)f(message)g(ab)r(out)g(the)h(commandline)g(options.)p +Black 0 2008 a Fd(-V)k({v)m(ersion)p Black 208 2155 a +Fi(Prin)n(t)26 b(v)n(ersion)g(information)h(ab)r(out)h(ulogd.)p +Black 0 2335 a Fd(-d)k({daemon)p Black 208 2482 a Fi(F)-7 +b(or)27 b(o\013)g(in)n(to)g(daemon)h(mo)r(de.)37 b(Unless)27 +b(y)n(ou)g(are)f(debugging,)h(y)n(ou)g(will)h(w)n(an)n(t)f(to)g(use)h +(this)g(most)f(of)h(the)g(time.)p Black 0 2662 a Fd(-c)k +({con\014g\014le)p Black 208 2809 a Fi(Using)j(this)h(commandline)g +(option,)i(an)d(alternate)g(con\014g)g(\014le)i(can)e(b)r(e)h(used.)62 +b(This)36 b(is)g(imp)r(ortan)n(t)f(if)i(m)n(ultiple)208 +2922 y(instances)27 b(of)g(ulogd)g(are)g(to)g(b)r(e)h(run)g(on)f(a)g +(single)g(mac)n(hine.)0 3064 y +SDict begin H.S end + 0 3064 a 0 3064 a +SDict begin 13.68 H.A end + 0 3064 +a 0 3064 a +SDict begin [ /View [/XYZ H.V] /Dest (section.4) cvn H.B /DEST pdfmark +end + 0 3064 a 197 x Fe(4)135 b(Av)-7 b(ailable)46 +b(plugins)0 3499 y Fi(It)38 b(is)g(imp)r(ortan)n(t)g(to)g(understand)f +(that)h(ulogd)g(without)g(plugins)g(do)r(es)f(nothing.)68 +b(It)38 b(will)h(receiv)n(e)d(pac)n(k)n(ets,)k(and)d(do)0 +3613 y(nothing)27 b(with)i(them.)0 3769 y(There)d(are)f(t)n(w)n(o)g +(kinds)h(of)g(plugins,)h(in)n(terpreter)e(and)h(output)g(plugins.)37 +b(In)n(terpreter)25 b(plugins)h(parse)f(the)h(pac)n(k)n(et,)g(output)0 +3883 y(plugins)h(write)h(the)g(in)n(terpreted)f(information)g(to)g +(some)g(log\014le/database/...)0 4020 y +SDict begin H.S end + 0 4020 a 0 4020 +a +SDict begin 13.68 H.A end + 0 4020 a 0 4020 a +SDict begin [ /View [/XYZ H.V] /Dest (subsection.4.1) cvn H.B /DEST +pdfmark end + 0 4020 a 155 x Fc(4.1)112 b(In)m(terpreter)37 +b(plugins)0 4385 y Fi(ulogd)27 b(comes)g(with)h(the)g(follo)n(wing)f +(in)n(terpreter)f(plugins:)0 4517 y +SDict begin H.S end + 0 4517 a 0 4517 a +SDict begin 13.68 H.A end + +0 4517 a 0 4517 a +SDict begin [ /View [/XYZ H.V] /Dest (subsubsection.4.1.1) cvn H.B +/DEST pdfmark end + 0 4517 a 140 x Fd(4.1.1)94 b(ulogd)p +527 4657 29 4 v 33 w(BASE.so)0 4867 y Fi(Basic)20 b(in)n(terpreter)f +(plugin)i(for)f(nfmark,)h(timestamp,)i(mac)d(address,)h(ip)g(header,)g +(tcp)g(header,)g(udp)g(header,)g(icmp)g(header,)0 4981 +y(ah/esp)27 b(header...)36 b(Most)27 b(p)r(eople)h(will)f(w)n(an)n(t)g +(to)h(load)f(this)h(v)n(ery)e(imp)r(ortan)n(t)h(plugin.)0 +5118 y +SDict begin H.S end + 0 5118 a 0 5118 a +SDict begin 13.68 H.A end + 0 5118 a 0 5118 a +SDict begin [ /View [/XYZ H.V] /Dest (subsubsection.4.1.2) cvn H.B +/DEST pdfmark end + 0 5118 a 136 +x Fd(4.1.2)94 b(ulogd)p 527 5254 29 4 v 33 w(PWSNIFF.so)0 +5464 y Fi(Example)31 b(in)n(terpreter)g(plugin)h(to)g(log)f(plain)n +(text)h(passw)n(ords)e(as)h(used)h(with)h(FTP)f(and)g(POP3.)48 +b(Don't)33 b(blame)e(me)i(for)0 5577 y(writing)i(this)i(plugin!)62 +b(The)35 b(proto)r(cols)g(are)g(inheren)n(tly)g(insecure,)j(and)d +(there)h(are)f(a)h(lot)f(of)h(other)f(to)r(ols)h(for)f(sni\016ng)0 +5691 y(passw)n(ords...)g(it's)28 b(just)g(an)f(example.)p +Black Black eop end +%%Page: 6 6 +TeXDict begin 6 5 bop 0 0 a +SDict begin /product where{pop product(Distiller)search{pop pop pop +version(.)search{exch pop exch pop(3011)eq{gsave newpath 0 0 moveto +closepath clip/Courier findfont 10 scalefont setfont 72 72 moveto(.)show +grestore}if}{pop}ifelse}{pop}ifelse}if end + 0 0 a Black 0 TeXcolorgray +0 -200 a +SDict begin H.S end + 0 -200 a 0 TeXcolorgray 0 TeXcolorgray 0 -200 +a +SDict begin H.R end + 0 -200 a 0 -200 a +SDict begin [ /View [/XYZ H.V] /Dest (page.6) cvn H.B /DEST pdfmark +end + 0 -200 a Black 0 -167 3900 5 v Fd(4.)74 +b(Av)-5 b(ailable)31 b(plugins)2992 b Fi(6)p Black 0 +79 a +SDict begin H.S end + 0 79 a 0 79 a +SDict begin 13.68 H.A end + 0 79 a 0 79 a +SDict begin [ /View [/XYZ H.V] /Dest (subsubsection.4.1.3) cvn H.B +/DEST pdfmark end + 0 79 a 83 x Fd(4.1.3)94 +b(ulogd)p 527 162 29 4 v 33 w(LOCAL.so)0 372 y Fi(This)29 +b(is)g(a)f('virtual)g(in)n(terpreter'.)40 b(It)29 b(do)r(esn't)g +(really)f(return)g(an)n(y)g(information)g(on)h(the)g(pac)n(k)n(et)f +(itself,)i(rather)d(the)j(lo)r(cal)0 485 y(system)i(time)i(and)e +(hostname.)51 b(Please)32 b(note)g(that)h(the)g(time)g(is)g(the)g(time) +g(at)g(the)g(time)g(of)f(logging,)h(not)f(the)h(pac)n(k)n(ets)0 +599 y(receiv)n(e)26 b(time.)0 715 y +SDict begin H.S end + 0 715 a 0 715 a +SDict begin 13.68 H.A end + 0 +715 a 0 715 a +SDict begin [ /View [/XYZ H.V] /Dest (subsection.4.2) cvn H.B /DEST +pdfmark end + 0 715 a 175 x Fc(4.2)112 b(Output)38 b(plugins)0 +1101 y Fi(ulogd)27 b(comes)g(with)h(the)g(follo)n(wing)f(output)h +(plugins:)0 1233 y +SDict begin H.S end + 0 1233 a 0 1233 a +SDict begin 13.68 H.A end + 0 1233 a 0 1233 +a +SDict begin [ /View [/XYZ H.V] /Dest (subsubsection.4.2.1) cvn H.B +/DEST pdfmark end + 0 1233 a 140 x Fd(4.2.1)94 b(ulogd)p 527 1373 29 4 +v 33 w(OPRINT.so)0 1583 y Fi(A)28 b(v)n(ery)e(simple)i(output)g(mo)r +(dule,)g(dumping)g(all)f(pac)n(k)n(ets)g(in)h(the)g(format)p +Black Black Black Black 208 1797 a Fa(===>PACKET)41 b(BOUNDARY)208 +1901 y(key=value)208 2005 y(key=value)208 2109 y(...)208 +2213 y(===>PACKET)g(BOUNDARY)208 2317 y(...)0 2540 y +Fi(to)27 b(a)h(\014le.)37 b(The)27 b(only)h(useful)g(application)e(is)i +(debugging.)0 2697 y(The)g(mo)r(dule)g(de\014nes)f(the)h(follo)n(wing)f +(con\014guration)f(directiv)n(es:)p Black 0 2920 a Fd(dump\014le)p +Black 208 3066 a Fi(The)h(\014lename)h(where)f(it)h(should)f(log)g(to.) +37 b(The)27 b(default)h(is)g Ff(/var/log/ulogd.p)o(kt)o(log)0 +3201 y +SDict begin H.S end + 0 3201 a 0 3201 a +SDict begin 13.68 H.A end + 0 3201 a 0 3201 a +SDict begin [ /View [/XYZ H.V] /Dest (subsubsection.4.2.2) cvn H.B +/DEST pdfmark end + 0 3201 a 138 +x Fd(4.2.2)94 b(ulogd)p 527 3339 29 4 v 33 w(LOGEMU.so)0 +3549 y Fi(An)33 b(output)g(mo)r(dule)g(whic)n(h)f(tries)h(to)f(em)n +(ulate)g(the)h(old)f(syslog-based)f(LOG)h(targed)f(as)h(far)g(as)g(p)r +(ossible.)51 b(Logging)31 b(is)0 3663 y(done)c(to)h(a)f(sep)r(erate)g +(text\014le)h(instead)f(of)h(syslog,)e(though.)0 3819 +y(The)i(mo)r(dule)g(de\014nes)f(the)h(follo)n(wing)f(con\014guration)f +(directiv)n(es:)p Black 0 4042 a Fd(\014le)p Black 208 +4189 a Fi(The)h(\014lename)h(where)f(it)h(should)f(log)g(to.)37 +b(The)27 b(default)h(is)g Ff(/var/log/ulogd.s)o(ys)o(log)o(em)o(u)p +Black 0 4369 a Fd(sync)p Black 208 4516 a Fi(Set)c(this)h(to)f(1)g(if)h +(y)n(ou)f(w)n(an)n(t)g(to)g(ha)n(v)n(e)f(y)n(our)g(log\014le)h(written) +h(sync)n(hronously)-7 b(.)33 b(This)25 b(ma)n(y)e(reduce)h(p)r +(erformance,)g(but)208 4629 y(mak)n(es)i(y)n(our)g(log-lines)h(app)r +(ear)f(immediately)-7 b(.)38 b(The)27 b(default)h(is)g +Ff(0)0 4761 y +SDict begin H.S end + 0 4761 a 0 4761 a +SDict begin 13.68 H.A end + 0 4761 a 0 4761 a +SDict begin [ /View [/XYZ H.V] /Dest (subsubsection.4.2.3) cvn H.B +/DEST pdfmark end + 0 4761 +a 141 x Fd(4.2.3)94 b(ulogd)p 527 4902 29 4 v 33 w(MYSQL.so)0 +5112 y Fi(An)31 b(output)h(plugin)f(for)g(logging)e(in)n(to)i(a)f(m)n +(ysql)h(database.)46 b(This)31 b(is)g(only)f(compiled)h(if)h(y)n(ou)e +(ha)n(v)n(e)g(the)h(m)n(ysql)f(libraries)0 5225 y(installed,)21 +b(and)e(the)h(con\014gure)e(script)i(w)n(as)e(able)h(to)h(detect)f +(them.)35 b(\(that)20 b(is:)33 b({with-m)n(ysql)18 b(w)n(as)h(sp)r +(eci\014ed)h(for)e(./con\014gure\))0 5382 y(The)26 b(plugin)f +(automagically)f(inserts)h(the)h(data)f(in)n(to)g(the)h(con\014gured)e +(table;)i(It)g(connects)f(to)h(m)n(ysql)e(during)i(the)f(startup)0 +5495 y(phase)33 b(of)g(ulogd)g(and)g(obtains)g(a)g(list)h(of)f(the)h +(columns)f(in)h(the)g(table.)54 b(Then)34 b(it)f(tries)g(to)h(resolv)n +(e)d(the)j(column)g(names)0 5609 y(against)27 b(k)n(eys)g(of)h(in)n +(terpreter)f(plugins.)38 b(This)27 b(w)n(a)n(y)g(y)n(ou)g(can)h(easily) +f(select)h(whic)n(h)g(information)f(y)n(ou)g(w)n(an)n(t)h(to)g(log)f(-) +g(just)0 5723 y(b)n(y)g(the)h(la)n(y)n(out)f(of)g(the)h(table.)p +Black Black eop end +%%Page: 7 7 +TeXDict begin 7 6 bop 0 0 a +SDict begin /product where{pop product(Distiller)search{pop pop pop +version(.)search{exch pop exch pop(3011)eq{gsave newpath 0 0 moveto +closepath clip/Courier findfont 10 scalefont setfont 72 72 moveto(.)show +grestore}if}{pop}ifelse}{pop}ifelse}if end + 0 0 a Black 0 TeXcolorgray +0 -200 a +SDict begin H.S end + 0 -200 a 0 TeXcolorgray 0 TeXcolorgray 0 -200 +a +SDict begin H.R end + 0 -200 a 0 -200 a +SDict begin [ /View [/XYZ H.V] /Dest (page.7) cvn H.B /DEST pdfmark +end + 0 -200 a Black 0 -167 3900 5 v Fd(4.)74 +b(Av)-5 b(ailable)31 b(plugins)2992 b Fi(7)p Black 0 +162 a(If,)27 b(for)f(example,)h(y)n(our)e(table)h(con)n(tains)g(a)g +(\014eld)h(called)f('ip)p 1876 162 25 4 v 30 w(saddr',)g(ulogd)g(will)h +(resolv)n(e)e(this)h(against)g(the)h(k)n(ey)f('ip.saddr')0 +275 y(and)h(put)i(the)f(ip)f(address)g(as)g(32bit)g(unsigned)g(in)n +(teger)g(in)n(to)g(the)h(table.)0 432 y(Y)-7 b(ou)30 +b(ma)n(y)g(w)n(an)n(t)g(to)g(ha)n(v)n(e)f(a)h(lo)r(ok)g(at)g(the)h +(\014le)g(')p Ff(doc/mysql.table)p Fi(')24 b(as)30 b(an)g(example)g +(table)g(including)h(\014elds)f(to)h(log)e(all)0 545 +y(k)n(eys)e(from)g(ulogd)p 583 545 V 29 w(BASE.so.)36 +b(Just)28 b(delete)f(the)h(\014elds)g(y)n(ou)f(are)f(not)i(in)n +(terested)f(in,)h(and)g(create)e(the)i(table.)0 702 y(The)g(mo)r(dule)g +(de\014nes)f(the)h(follo)n(wing)f(con\014guration)f(directiv)n(es:)p +Black 0 922 a Fd(table)p Black 208 1068 a Fi(Name)h(of)h(the)g(table)f +(to)h(whic)n(h)f(ulogd)g(should)h(log.)p Black 0 1247 +a Fd(ldb)p Black 208 1393 a Fi(Name)f(of)h(the)g(m)n(ysql)f(database.)p +Black 0 1572 a Fd(host)p Black 208 1718 a Fi(Name)g(of)h(the)g(m)n +(ysql)f(database)f(host.)p Black 0 1897 a Fd(p)s(ort)p +Black 208 2043 a Fi(TCP)h(p)r(ort)g(n)n(um)n(b)r(er)g(of)h(m)n(ysql)f +(database)f(serv)n(er.)p Black 0 2221 a Fd(user)p Black +208 2368 a Fi(Name)h(of)h(the)g(m)n(ysql)f(user.)p Black +0 2546 a Fd(pass)p Black 208 2692 a Fi(P)n(assw)n(ord)d(for)j(m)n +(ysql.)0 2824 y +SDict begin H.S end + 0 2824 a 0 2824 a +SDict begin 13.68 H.A end + 0 2824 a 0 2824 a +SDict begin [ /View [/XYZ H.V] /Dest (subsubsection.4.2.4) cvn H.B +/DEST pdfmark end + 0 +2824 a 141 x Fd(4.2.4)94 b(ulogd)p 527 2965 29 4 v 33 +w(PGSQL.so)0 3175 y Fi(An)23 b(output)g(plugin)g(for)f(logging)f(in)n +(to)h(a)g(p)r(ostgresql)g(database.)34 b(This)22 b(is)h(only)f +(compiled)g(if)h(y)n(ou)f(ha)n(v)n(e)g(the)h(m)n(ysql)e(libraries)0 +3288 y(installed,)h(and)f(the)h(con\014gure)d(script)i(w)n(as)f(able)h +(to)g(detect)g(them.)36 b(\(that)21 b(is:)34 b({with-pgsql)20 +b(w)n(as)g(sp)r(eci\014ed)h(for)f(./con\014gure\))0 3445 +y(The)27 b(plugin)g(automagically)e(inserts)i(the)g(data)f(in)n(to)h +(the)g(con\014gured)f(table;)i(It)f(connects)f(to)h(pgsql)g(during)f +(the)h(startup)0 3558 y(phase)33 b(of)g(ulogd)g(and)g(obtains)g(a)g +(list)h(of)f(the)h(columns)f(in)h(the)g(table.)54 b(Then)34 +b(it)f(tries)g(to)h(resolv)n(e)d(the)j(column)g(names)0 +3672 y(against)27 b(k)n(eys)g(of)h(in)n(terpreter)f(plugins.)38 +b(This)27 b(w)n(a)n(y)g(y)n(ou)g(can)h(easily)f(select)h(whic)n(h)g +(information)f(y)n(ou)g(w)n(an)n(t)h(to)g(log)f(-)g(just)0 +3785 y(b)n(y)g(the)h(la)n(y)n(out)f(of)g(the)h(table.)0 +3942 y(If,)f(for)f(example,)h(y)n(our)e(table)h(con)n(tains)g(a)g +(\014eld)h(called)f('ip)p 1876 3942 25 4 v 30 w(saddr',)g(ulogd)g(will) +h(resolv)n(e)e(this)h(against)g(the)h(k)n(ey)f('ip.saddr')0 +4055 y(and)h(put)i(the)f(ip)f(address)g(as)g(32bit)g(unsigned)g(in)n +(teger)g(in)n(to)g(the)h(table.)0 4212 y(Y)-7 b(ou)30 +b(ma)n(y)g(w)n(an)n(t)g(to)g(ha)n(v)n(e)f(a)h(lo)r(ok)g(at)g(the)h +(\014le)g(')p Ff(doc/mysql.table)p Fi(')24 b(as)30 b(an)g(example)g +(table)g(including)h(\014elds)f(to)h(log)e(all)0 4325 +y(k)n(eys)e(from)g(ulogd)p 583 4325 V 29 w(BASE.so.)36 +b(Just)28 b(delete)f(the)h(\014elds)g(y)n(ou)f(are)f(not)i(in)n +(terested)f(in,)h(and)g(create)e(the)i(table.)0 4482 +y(The)g(mo)r(dule)g(de\014nes)f(the)h(follo)n(wing)f(con\014guration)f +(directiv)n(es:)p Black 0 4702 a Fd(table)p Black 208 +4848 a Fi(Name)h(of)h(the)g(table)f(to)h(whic)n(h)f(ulogd)g(should)h +(log.)p Black 0 5027 a Fd(db)p Black 208 5173 a Fi(Name)f(of)h(the)g +(database.)p Black 0 5352 a Fd(host)p Black 208 5498 +a Fi(Name)f(of)h(the)g(m)n(ysql)f(database)f(host.)p +Black 0 5677 a Fd(p)s(ort)p Black 208 5823 a Fi(TCP)h(p)r(ort)g(n)n(um) +n(b)r(er)g(of)h(database)e(serv)n(er.)p Black Black eop +end +%%Page: 8 8 +TeXDict begin 8 7 bop 0 0 a +SDict begin /product where{pop product(Distiller)search{pop pop pop +version(.)search{exch pop exch pop(3011)eq{gsave newpath 0 0 moveto +closepath clip/Courier findfont 10 scalefont setfont 72 72 moveto(.)show +grestore}if}{pop}ifelse}{pop}ifelse}if end + 0 0 a Black 0 TeXcolorgray +0 -200 a +SDict begin H.S end + 0 -200 a 0 TeXcolorgray 0 TeXcolorgray 0 -200 +a +SDict begin H.R end + 0 -200 a 0 -200 a +SDict begin [ /View [/XYZ H.V] /Dest (page.8) cvn H.B /DEST pdfmark +end + 0 -200 a Black 0 -167 3900 5 v Fd(4.)74 +b(Av)-5 b(ailable)31 b(plugins)2992 b Fi(8)p Black Black +0 162 a Fd(user)p Black 208 306 a Fi(Name)27 b(of)h(the)g(sql)f(user.)p +Black 0 482 a Fd(pass)p Black 208 627 a Fi(P)n(assw)n(ord)d(for)j(sql)h +(user.)0 757 y +SDict begin H.S end + 0 757 a 0 757 a +SDict begin 13.68 H.A end + 0 757 a 0 757 a +SDict begin [ /View [/XYZ H.V] /Dest (subsubsection.4.2.5) cvn H.B +/DEST pdfmark end + 0 757 +a 140 x Fd(4.2.5)94 b(ulogd)p 527 897 29 4 v 33 w(PCAP)-8 +b(.so)0 1108 y Fi(An)35 b(output)g(plugin)g(that)f(can)g(b)r(e)h(used)g +(to)f(generate)f(libp)r(cap-st)n(yle)h(pac)n(k)n(et)g(log\014les.)56 +b(This)35 b(can)f(b)r(e)h(useful)g(for)f(later)0 1221 +y(analysing)26 b(the)i(pac)n(k)n(et)f(log)f(with)j(to)r(ols)e(lik)n(e)g +(tcp)r(dump)i(or)d(ethereal.)0 1378 y(The)i(mo)r(dule)g(de\014nes)f +(the)h(follo)n(wing)f(con\014guration)f(directiv)n(es:)p +Black 0 1592 a Fd(\014le)p Black 208 1737 a Fi(The)h(\014lename)h +(where)f(it)h(should)f(log)g(to.)37 b(The)27 b(default)h(is:)37 +b Ff(/var/log/ulogd.pc)o(ap)p Black 0 1912 a Fd(sync)p +Black 208 2057 a Fi(Set)21 b(this)h(to)f Ff(1)g Fi(if)h(y)n(ou)f(w)n +(an)n(t)f(to)i(ha)n(v)n(e)e(y)n(our)g(p)r(cap)h(log\014le)g(written)g +(sync)n(hronously)-7 b(.)33 b(This)22 b(ma)n(y)e(reduce)h(p)r +(erformance,)208 2171 y(but)28 b(mak)n(es)e(y)n(our)h(pac)n(k)n(ets)f +(app)r(ear)h(immediately)g(in)h(the)g(\014le)g(on)f(disk.)37 +b(The)28 b(default)g(is)f Ff(0)0 2301 y +SDict begin H.S end + 0 2301 a 0 2301 +a +SDict begin 13.68 H.A end + 0 2301 a 0 2301 a +SDict begin [ /View [/XYZ H.V] /Dest (subsubsection.4.2.6) cvn H.B +/DEST pdfmark end + 0 2301 a 140 x Fd(4.2.6)94 b(ulogd)p +527 2441 29 4 v 33 w(SQLITE3.so)0 2651 y Fi(An)38 b(output)g(plugin)f +(for)g(logging)e(in)n(to)j(a)e(SQLITE)h(v3)g(database.)64 +b(This)38 b(is)f(only)g(compiled)g(if)h(y)n(ou)e(ha)n(v)n(e)g(the)i +(sqlite)0 2765 y(libraries)26 b(installed,)h(and)f(the)i(con\014gure)e +(script)g(w)n(as)g(able)h(to)g(detect)g(them.)37 b(\(that)28 +b(is:)36 b({with-sqlite3)26 b(w)n(as)g(sp)r(eci\014ed)i(for)0 +2879 y(./con\014gure\))0 3035 y(The)23 b(plugin)h(automagically)d +(inserts)i(the)g(data)g(in)n(to)g(the)h(con\014gured)e(table;)j(It)e +(op)r(ens)g(the)h(sqlite)f(db)h(during)f(the)g(startup)0 +3149 y(phase)33 b(of)g(ulogd)g(and)g(obtains)g(a)g(list)h(of)f(the)h +(columns)f(in)h(the)g(table.)54 b(Then)34 b(it)f(tries)g(to)h(resolv)n +(e)d(the)j(column)g(names)0 3262 y(against)27 b(k)n(eys)g(of)h(in)n +(terpreter)f(plugins.)38 b(This)27 b(w)n(a)n(y)g(y)n(ou)g(can)h(easily) +f(select)h(whic)n(h)g(information)f(y)n(ou)g(w)n(an)n(t)h(to)g(log)f(-) +g(just)0 3376 y(b)n(y)g(the)h(la)n(y)n(out)f(of)g(the)h(table.)0 +3532 y(If,)f(for)f(example,)h(y)n(our)e(table)h(con)n(tains)g(a)g +(\014eld)h(called)f('ip)p 1876 3532 25 4 v 30 w(saddr',)g(ulogd)g(will) +h(resolv)n(e)e(this)h(against)g(the)h(k)n(ey)f('ip.saddr')0 +3646 y(and)h(put)i(the)f(ip)f(address)g(as)g(32bit)g(unsigned)g(in)n +(teger)g(in)n(to)g(the)h(table.)0 3802 y(Y)-7 b(ou)26 +b(ma)n(y)f(w)n(an)n(t)g(to)h(ha)n(v)n(e)f(a)g(lo)r(ok)g(at)h(the)g +(\014le)g(')p Ff(doc/sqlite3.tabl)o(e)p Fi(')20 b(as)25 +b(an)h(example)f(table)h(including)g(\014elds)g(to)f(log)g(all)0 +3916 y(k)n(eys)i(from)g(ulogd)p 583 3916 V 29 w(BASE.so.)36 +b(Just)28 b(delete)f(the)h(\014elds)g(y)n(ou)f(are)f(not)i(in)n +(terested)f(in,)h(and)g(create)e(the)i(table.)0 4072 +y(The)g(mo)r(dule)g(de\014nes)f(the)h(follo)n(wing)f(con\014guration)f +(directiv)n(es:)p Black 0 4287 a Fd(table)p Black 208 +4431 a Fi(Name)h(of)h(the)g(table)f(to)h(whic)n(h)f(ulogd)g(should)h +(log.)p Black 0 4607 a Fd(db)p Black 208 4752 a Fi(Name)f(of)h(the)g +(database.)p Black 0 4927 a Fd(bu\013er)p Black 208 5072 +a Fi(Size)f(of)h(the)g(sqlite)f(bu\013er.)0 5202 y +SDict begin H.S end + 0 +5202 a 0 5202 a +SDict begin 13.68 H.A end + 0 5202 a 0 5202 a +SDict begin [ /View [/XYZ H.V] /Dest (subsubsection.4.2.7) cvn H.B +/DEST pdfmark end + 0 5202 a 141 x Fd(4.2.7)94 +b(ulogd)p 527 5343 29 4 v 33 w(SYSLOG.so)0 5553 y Fi(An)36 +b(output)g(plugin)g(that)f(really)g(logs)f(via)h(syslogd.)59 +b(Lines)36 b(will)g(lo)r(ok)e(exactly)h(lik)n(e)g(prin)n(ted)h(with)g +(traditional)e(LOG)0 5666 y(target.)0 5823 y(The)28 b(mo)r(dule)g +(de\014nes)f(the)h(follo)n(wing)f(con\014guration)f(directiv)n(es:)p +Black Black eop end +%%Page: 9 9 +TeXDict begin 9 8 bop 0 0 a +SDict begin /product where{pop product(Distiller)search{pop pop pop +version(.)search{exch pop exch pop(3011)eq{gsave newpath 0 0 moveto +closepath clip/Courier findfont 10 scalefont setfont 72 72 moveto(.)show +grestore}if}{pop}ifelse}{pop}ifelse}if end + 0 0 a Black 0 TeXcolorgray +0 -200 a +SDict begin H.S end + 0 -200 a 0 TeXcolorgray 0 TeXcolorgray 0 -200 +a +SDict begin H.R end + 0 -200 a 0 -200 a +SDict begin [ /View [/XYZ H.V] /Dest (page.9) cvn H.B /DEST pdfmark +end + 0 -200 a Black 0 -167 3900 5 v Fd(5.)74 +b(QUESTIONS)31 b(/)h(COMMENTS)2455 b Fi(9)p Black Black +0 162 a Fd(facilit)m(y)p Black 208 308 a Fi(The)27 b(syslog)f(facilit)n +(y)i(\(LOG)p 1115 308 25 4 v 30 w(D)n(AEMON,)f(LOG)p +1760 308 V 30 w(KERN,)g(LOG)p 2267 308 V 29 w(LOCAL0)g(..)37 +b(LOG)p 2921 308 V 30 w(LOCAL7,)26 b(LOG)p 3515 308 V +30 w(USER\))p Black 0 488 a Fd(lev)m(el)p Black 208 635 +a Fi(The)80 b(syslog)e(lev)n(el)i(\(LOG)p 1187 635 V +29 w(EMER)n(G,)g(LOG)p 1815 635 V 29 w(ALER)-7 b(T,)80 +b(LOG)p 2414 635 V 30 w(CRIT,)g(LOG)p 2940 635 V 29 w(ERR,)g(LOG)p +3433 635 V 30 w(W)-9 b(ARNING,)208 749 y(LOG)p 395 749 +V 29 w(NOTICE,)27 b(LOG)p 990 749 V 30 w(INF)n(O,)g(LOG)p +1461 749 V 29 w(DEBUG\))0 895 y +SDict begin H.S end + 0 895 a 0 895 a +SDict begin 13.68 H.A end + 0 895 +a 0 895 a +SDict begin [ /View [/XYZ H.V] /Dest (section.5) cvn H.B /DEST pdfmark +end + 0 895 a 192 x Fe(5)135 b(QUESTIONS)44 b(/)i(COMMENTS)0 +1326 y Fi(All)28 b(commen)n(ts)f(/)g(questions)g(/)h(...)37 +b(are)26 b(appreciated.)0 1482 y(Just)h(drop)g(me)h(a)f(note)h(to)f +(laforge@gn)n(umonks.org)0 1639 y(Please)f(note)i(also)e(that)i(there)g +(is)f(no)n(w)g(a)g(mailinglist,)h(ulogd@lists.gn)n(umonks.org.)33 +b(Y)-7 b(ou)28 b(can)f(subscrib)r(e)g(at)0 1795 y(.)0 +1952 y(The)h(preferred)e(metho)r(d)i(for)f(rep)r(orting)g(bugs)g(is)h +(the)g(net\014lter)f(bugzilla)g(system,)h(a)n(v)-5 b(ailable)26 +b(at)83 b(.)p Black Black eop end +%%Trailer + +userdict /end-hook known{end-hook}if +%%EOF diff --git a/doc/ulogd.html b/doc/ulogd.html new file mode 100644 index 0000000..8099638 --- /dev/null +++ b/doc/ulogd.html @@ -0,0 +1,422 @@ + + + + + ULOGD - the Userspace Logging Daemon + + +

ULOGD - the Userspace Logging Daemon

+ +

Harald Welte <laforge@gnumonks.org>

Revision $Revision: 5846 $, $Date: 2005-07-12 17:33:23 +0200 (Tue, 12 Jul 2005) $ +
+This is the documentation for ulogd, the Userspace logging daemon. +ulogd makes use of the Linux >= 2.4.x packet filter subsystem (iptables) and +the ULOG target for iptables. +
+

1. DESIGN

+ +

1.1 CONCEPT +

+ +

I want to provide a flexible, almost universal logging daemon for my netfilter +ULOG target. It is not optimized in any way, the goal is to keep as simple as +possible. These are my thoughts about how the architecture which is most +capable of doing that:

+

+

+
Interpreter plugins

It should be possible to add plugins / runtime modules for new protocols, etc. +For example the standard logging daemon provides source-ip, dest-ip, +source-port, dest-port, etc. Logging for various other protocols (GRE, +IPsec, ...) may be implemented as modules.

+ +
Output plugins

... describe how and where to put the information gained by logging plugins. +The easiest way is to build a line per packet and fprint it to a file. +Some people might want to log into a SQL database or want an output +conforming to the intrusion detection systems communication draft from the +IETF.

+ +
+

+ +

1.2 DETAILS +

+ +

The major clue is providing a framework which is as flexible as possible. +Nobody knows what strange network protocols are out there :) Flexibility +depends on the communication between the output of the logging plugins +and input of the output plugins.

+

Rusty advised me to use some kind of type-key-value triples, which is in fact +what I implemented.

+

One issue is, of course, performance. Up to ulogd 0.3, ulogd did several +linked list iterations and about 30 malloc() calls _per packet_. This +changed with the new >= 0.9 revisions: +

    +
  • Not a single dynamic allocation in the core during runtime. +Everything is pre-allocated at start of ulogd to provide the highest +possible throughput.
  • +
  • Hash tables in addition to the linked lists. Linked lists are only +traversed if we really want to access each element of the list.
  • +
+

+ +

2. INSTALLATION

+ + +

2.1 Linux kernel +

+ +

First you will need a recent 2.4.x kernel. If you have a kernel >= +2.4.18-pre8, it already has the kernel support for ULOG (ipt_ULOG.o).

+

If you have an older kernel version (between 2.4.0 and 2.4.18-pre6), you +can use the patch-o-matic system of netfilter/iptables, as described in +the following section.

+ +

2.2 ipt_ULOG from netfilter/iptables patch-o-matic +

+ +

You only need to read this chapter if you have a 2.4.x kernel <= +2.4.18-pre6.

+

In order to put the ipt_ULOG module into your kernel source,you need the latest +iptables package, or even better: the latest CVS snapshot. A description how to +obtain this is provided on the netfilter +homepage +http://www.netfilter.org/.

+

To run patch-o-matic, just type +

+
+make patch-o-matic
+
+
+ +in the userspace directory of netfilter CVS.

+ +

2.3 ulogd +

+ +

Recompiling the source

+ +

Download the ulogd package from +http://ftp.netfilter.org/pub/ulogd/ and +untar it.

+

If you want to build ulogd with MySQL support, type './configure --with-mysql'. You may also have to specify the path of the mysql libraries using '--with-mysql=path'. To build ulogd without MySQL support, just use './configure'.

+

To compile and install the program, call 'make install'.

+ +

Using a precompiled package

+ +

I also provide a SRPM, which should compile on almost any rpm-based distribution. It is available at +http://ftp.netfilter.org/pub/ulogd/

+

Just download the package and do the usual 'rpm --rebuild <file>'.

+ +

3. Configuration

+ +

3.1 iptables ULOG target +

+ +

Quick Setup

+ +

Just add rules using the ULOG target to your firewalling chain. A very basic +example: +

+
+iptables -A FORWARD -j ULOG --ulog-nlgroup 32 --ulog-prefix foo 
+
+
+

+

To increase logging performance, try to use the +

+
+--ulog-qthreshold N
+
+
+ +option (where 1 < N <= 50). The number you specify is the amount of packets +batched together in one multipart netlink message. If you set this to 20, the +kernel schedules ulogd only once every 20 packets. All 20 packets are then +processed by ulogd. This reduces the number of context switches between kernel +and userspace.

+

Of course you can combine the ULOG target with the different netfilter match +modules. For a more detailed description, have a look at the netfilter +HOWTO's, available on the netfilter homepage.

+

ULOG target reference

+ +

+

+
--ulog-nlgroup N

The number of the netlink multicast group to which ULOG'ed packets are sent. +You will have to use the same group number in the ULOG target and ulogd in +order to make logging work.

+
--ulog-cprange N

Copyrange. This works like the 'snaplen' parameter of tcpdump. You can specify +a number of bytes up to which the packet is copied. If you say '40', you will +receive the first fourty bytes of every packet. Leave it to 0

+
--ulog-qthreshold N

Queue threshold. If a packet is matched by the iptables rule, and already N +packets are in the queue, the queue is flushed to userspace. You can use this +to implement a policy like: Use a big queue in order to gain high performance, +but still have certain packets logged immediately to userspace.

+
--ulog-prefix STRING

A string that is associated with every packet logged by this rule. You can use +this option to later tell from which rule the packet was logged.

+
+

+ +

ipt_ULOG module parameters

+ +

The ipt_ULOG kernel module has a couple of module loadtime parameters which can +(and should) be tuned to accomodate the needs of the application: +

+
nlbufsiz N

Netlink buffer size. A buffer of the specified size N is allocated for every +netlink group that is used. Please note that due to restrictions of the kernel +memory allocator, we cannot have a buffer size > 128kBytes. Larger buffer +sizes increase the performance, since less kernel/userspace context switches +are needed for the same amount of packets. The backside of this performance +gain is a potentially larger delay. The default value is 4096 bytes, which is +quite small.

+
flushtimeout N

The flushtimeout determines, after how many clock ticks (on alpha: 1ms, on +x86 and most other platforms: 10ms time units) the buffer/queue is to be +flushed, even if it is not full. This can be used to have the advantage of a +large buffer, but still a finite maximum delay introduced. The default value +is set to 10 seconds.

+
+ +Example: +
+
+modprobe ipt_ULOG nlbufsiz=65535 flushtimeout=100
+
+
+ +This would use a buffer size of 64k and a flushtimeout of 100 clockticks (1 second on x86).

+ +

3.2 ulogd +

+ +

ulogd is what this is all about, so let's describe it's configuration...

+

ulogd configfile syntax reference

+ +

All configurable parameters of ulogd are in the configfile, typically located +at '/etc/ulogd.conf'.

+

The following configuration parameters are available: +

+
nlgroup

The netlink multicast group, which ulgogd should bind to. This is the same as +given with the '--ulog-nlgroup' option to iptables.

+
logfile

The main logfile, where ulogd reports any errors, warnings and other unexpected conditions. Apart from a regular filename, the following special values can be used; ``syslog'' to log via the unix syslog(3) mechanism. ``stdout'' to log to stdout.

+
loglevel

This specifies, how verbose the logging to logfile is. Currently defined +loglevels are: 1=debug information, 3=informational messages, 5=noticable +exceptional conditions, 7=error conditions, 8=fatal errors, program abort.

+
plugin

This option is followed by a filename of a ulogd plugin, which ulogd shold load +upon initialization. This option may appear more than once.

+
rmem

Size of the netlink socket receive memory. You should set this to at least the +size of the kernel buffer (nlbufsiz parameter of the ipt_ULOG module). Please +note that there is a maximum limit in /proc/sys/net/core/rmem_max which you +cannot exceed by increasing the ``rmem'' parameter. You may need to raise the +system-wide maximum limit before.

+
bufsize

Size of the receive buffer. You should set this to at least the socket receive buffer (rmem).

+
+

+

ulogd commandline option reference

+ +

Apart from the configfile, there are a couple of commandline options to ulogd: +

+
-h --help

Print a help message about the commandline options.

+
-V --version

Print version information about ulogd.

+
-d --daemon

For off into daemon mode. Unless you are debugging, you will want to use this +most of the time.

+
-c --configfile

Using this commandline option, an alternate config file can be used. This is +important if multiple instances of ulogd are to be run on a single machine.

+
+

+ +

4. Available plugins

+ +

It is important to understand that ulogd without plugins does nothing. It will receive packets, and do nothing with them.

+

There are two kinds of plugins, interpreter and output plugins. Interpreter +plugins parse the packet, output plugins write the interpreted information to +some logfile/database/...

+ +

4.1 Interpreter plugins +

+ +

ulogd comes with the following interpreter plugins:

+

ulogd_BASE.so

+ +

Basic interpreter plugin for nfmark, timestamp, mac address, ip header, tcp +header, udp header, icmp header, ah/esp header... Most people will want to load +this very important plugin.

+

ulogd_PWSNIFF.so

+ +

Example interpreter plugin to log plaintext passwords as used with FTP and +POP3. Don't blame me for writing this plugin! The protocols are inherently +insecure, and there are a lot of other tools for sniffing passwords... it's +just an example.

+

ulogd_LOCAL.so

+ +

This is a 'virtual interpreter'. It doesn't really return any information on +the packet itself, rather the local system time and hostname. Please note that +the time is the time at the time of logging, not the packets receive time.

+ +

4.2 Output plugins +

+ +

ulogd comes with the following output plugins:

+ +

ulogd_OPRINT.so

+ +

A very simple output module, dumping all packets in the format +

+
+===>PACKET BOUNDARY
+key=value
+key=value
+...
+===>PACKET BOUNDARY
+...
+
+
+ +to a file. The only useful application is debugging.

+

The module defines the following configuration directives: +

+
dumpfile

The filename where it should log to. The default is +/var/log/ulogd.pktlog

+
+

+ +

ulogd_LOGEMU.so

+ +

An output module which tries to emulate the old syslog-based LOG targed as far +as possible. Logging is done to a seperate textfile instead of syslog, though.

+

The module defines the following configuration directives: +

+
file

The filename where it should log to. The default is +/var/log/ulogd.syslogemu

+
sync

Set this to 1 if you want to have your logfile written +synchronously. This may reduce performance, but makes your log-lines appear +immediately. The default is 0

+
+

+ +

ulogd_MYSQL.so

+ +

An output plugin for logging into a mysql database. This is only compiled if +you have the mysql libraries installed, and the configure script was able to +detect them. (that is: --with-mysql was specified for ./configure)

+ +

The plugin automagically inserts the data into the configured table; It +connects to mysql during the startup phase of ulogd and obtains a list of the +columns in the table. Then it tries to resolve the column names against keys of +interpreter plugins. This way you can easily select which information you want +to log - just by the layout of the table.

+ +

If, for example, your table contains a field called 'ip_saddr', ulogd will +resolve this against the key 'ip.saddr' and put the ip address as 32bit +unsigned integer into the table.

+ +

You may want to have a look at the file 'doc/mysql.table' as an +example table including fields to log all keys from ulogd_BASE.so. Just delete +the fields you are not interested in, and create the table.

+ +

The module defines the following configuration directives: +

+
table

Name of the table to which ulogd should log.

+
ldb

Name of the mysql database.

+
host

Name of the mysql database host.

+
port

TCP port number of mysql database server.

+
user

Name of the mysql user.

+
pass

Password for mysql.

+
+

+ +

ulogd_PGSQL.so

+ +

An output plugin for logging into a postgresql database. This is only compiled +if you have the mysql libraries installed, and the configure script was able to +detect them. (that is: --with-pgsql was specified for ./configure)

+ +

The plugin automagically inserts the data into the configured table; It +connects to pgsql during the startup phase of ulogd and obtains a list of the +columns in the table. Then it tries to resolve the column names against keys of +interpreter plugins. This way you can easily select which information you want +to log - just by the layout of the table.

+ +

If, for example, your table contains a field called 'ip_saddr', ulogd will +resolve this against the key 'ip.saddr' and put the ip address as 32bit +unsigned integer into the table.

+ +

You may want to have a look at the file 'doc/mysql.table' as an +example table including fields to log all keys from ulogd_BASE.so. Just delete +the fields you are not interested in, and create the table.

+ +

The module defines the following configuration directives: +

+
table

Name of the table to which ulogd should log.

+
db

Name of the database.

+
host

Name of the mysql database host.

+
port

TCP port number of database server.

+
user

Name of the sql user.

+
pass

Password for sql user.

+
+

+ +

ulogd_PCAP.so

+ +

An output plugin that can be used to generate libpcap-style packet logfiles. +This can be useful for later analysing the packet log with tools like tcpdump +or ethereal.

+

The module defines the following configuration directives: +

+
file

The filename where it should log to. The default is: +/var/log/ulogd.pcap

+
sync

Set this to 1 if you want to have your pcap logfile written +synchronously. This may reduce performance, but makes your packets appear +immediately in the file on disk. The default is 0

+
+

+ +

ulogd_SQLITE3.so

+ +

An output plugin for logging into a SQLITE v3 database. This is only compiled +if you have the sqlite libraries installed, and the configure script was able to +detect them. (that is: --with-sqlite3 was specified for ./configure)

+ +

The plugin automagically inserts the data into the configured table; It +opens the sqlite db during the startup phase of ulogd and obtains a list of the +columns in the table. Then it tries to resolve the column names against keys of +interpreter plugins. This way you can easily select which information you want +to log - just by the layout of the table.

+ +

If, for example, your table contains a field called 'ip_saddr', ulogd will +resolve this against the key 'ip.saddr' and put the ip address as 32bit +unsigned integer into the table.

+ +

You may want to have a look at the file 'doc/sqlite3.table' as an +example table including fields to log all keys from ulogd_BASE.so. Just delete +the fields you are not interested in, and create the table.

+ +

The module defines the following configuration directives: +

+
table

Name of the table to which ulogd should log.

+
db

Name of the database.

+
buffer

Size of the sqlite buffer.

+
+

+

ulogd_SYSLOG.so

+ +

An output plugin that really logs via syslogd. Lines will look exactly like printed with traditional LOG target.

+ +

The module defines the following configuration directives: +

+
facility

The syslog facility (LOG_DAEMON, LOG_KERN, LOG_LOCAL0 .. LOG_LOCAL7, LOG_USER)

+
level

The syslog level (LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG)

+
+

+

5. QUESTIONS / COMMENTS

+ +

All comments / questions / ... are appreciated.

+

Just drop me a note to laforge@gnumonks.org

+

Please note also that there is now a mailinglist, ulogd@lists.gnumonks.org. +You can subscribe at +http://lists.gnumonks.org/mailman/listinfo/ulogd/.

+

+The preferred method for reporting bugs is the netfilter bugzilla system, +available at +http://bugzilla.netfilter.org/.

+ + + diff --git a/doc/ulogd.sgml b/doc/ulogd.sgml new file mode 100644 index 0000000..d534662 --- /dev/null +++ b/doc/ulogd.sgml @@ -0,0 +1,449 @@ + + + + +
+ +ULOGD - the Userspace Logging Daemon +Harald Welte <laforge@gnumonks.org> +Revision $Revision: 5846 $, $Date: 2005-07-12 17:33:23 +0200 (Tue, 12 Jul 2005) $ + + +This is the documentation for ulogd, the Userspace logging daemon. +ulogd makes use of the Linux >= 2.4.x packet filter subsystem (iptables) and +the ULOG target for iptables. + + + + +DESIGN + +CONCEPT +

+I want to provide a flexible, almost universal logging daemon for my netfilter +ULOG target. It is not optimized in any way, the goal is to keep as simple as +possible. These are my thoughts about how the architecture which is most +capable of doing that: +

+ +Interpreter plugins +It should be possible to add plugins / runtime modules for new protocols, etc. +For example the standard logging daemon provides source-ip, dest-ip, +source-port, dest-port, etc. Logging for various other protocols (GRE, +IPsec, ...) may be implemented as modules. + +Output plugins +... describe how and where to put the information gained by logging plugins. +The easiest way is to build a line per packet and fprint it to a file. +Some people might want to log into a SQL database or want an output +conforming to the intrusion detection systems communication draft from the +IETF. + + + +DETAILS +

+The major clue is providing a framework which is as flexible as possible. +Nobody knows what strange network protocols are out there :) Flexibility +depends on the communication between the output of the logging plugins +and input of the output plugins. +

+Rusty advised me to use some kind of type-key-value triples, which is in fact +what I implemented. +

+One issue is, of course, performance. Up to ulogd 0.3, ulogd did several +linked list iterations and about 30 malloc() calls _per packet_. This +changed with the new >= 0.9 revisions: + +Not a single dynamic allocation in the core during runtime. +Everything is pre-allocated at start of ulogd to provide the highest +possible throughput. +Hash tables in addition to the linked lists. Linked lists are only +traversed if we really want to access each element of the list. + + +INSTALLATION +

+Linux kernel +

+First you will need a recent 2.4.x kernel. If you have a kernel >= +2.4.18-pre8, it already has the kernel support for ULOG (ipt_ULOG.o). +

+If you have an older kernel version (between 2.4.0 and 2.4.18-pre6), you +can use the patch-o-matic system of netfilter/iptables, as described in +the following section. + +ipt_ULOG from netfilter/iptables patch-o-matic +

+You only need to read this chapter if you have a 2.4.x kernel <= +2.4.18-pre6. +

+In order to put the ipt_ULOG module into your kernel source,you need the latest +iptables package, or even better: the latest CVS snapshot. A description how to +obtain this is provided on the netfilter +homepage . +

+To run patch-o-matic, just type + +make patch-o-matic + +in the userspace directory of netfilter CVS. + +ulogd +Recompiling the source +

+Download the ulogd package from and +untar it. +

+If you want to build ulogd with MySQL support, type './configure --with-mysql'. You may also have to specify the path of the mysql libraries using '--with-mysql=path'. To build ulogd without MySQL support, just use './configure'. +

+To compile and install the program, call 'make install'. + +Using a precompiled package +

+I also provide a SRPM, which should compile on almost any rpm-based distribution. It is available at +

+Just download the package and do the usual 'rpm --rebuild <file>'. + +Configuration +iptables ULOG target +Quick Setup +

+Just add rules using the ULOG target to your firewalling chain. A very basic +example: + +iptables -A FORWARD -j ULOG --ulog-nlgroup 32 --ulog-prefix foo + +

+To increase logging performance, try to use the + +--ulog-qthreshold N + +option (where 1 < N <= 50). The number you specify is the amount of packets +batched together in one multipart netlink message. If you set this to 20, the +kernel schedules ulogd only once every 20 packets. All 20 packets are then +processed by ulogd. This reduces the number of context switches between kernel +and userspace. +

+Of course you can combine the ULOG target with the different netfilter match +modules. For a more detailed description, have a look at the netfilter +HOWTO's, available on the netfilter homepage. +ULOG target reference +

+ +--ulog-nlgroup N +The number of the netlink multicast group to which ULOG'ed packets are sent. +You will have to use the same group number in the ULOG target and ulogd in +order to make logging work. +--ulog-cprange N +Copyrange. This works like the 'snaplen' parameter of tcpdump. You can specify +a number of bytes up to which the packet is copied. If you say '40', you will +receive the first fourty bytes of every packet. Leave it to 0 +--ulog-qthreshold N +Queue threshold. If a packet is matched by the iptables rule, and already N +packets are in the queue, the queue is flushed to userspace. You can use this +to implement a policy like: Use a big queue in order to gain high performance, +but still have certain packets logged immediately to userspace. +--ulog-prefix STRING +A string that is associated with every packet logged by this rule. You can use +this option to later tell from which rule the packet was logged. + + +ipt_ULOG module parameters +

+The ipt_ULOG kernel module has a couple of module loadtime parameters which can +(and should) be tuned to accomodate the needs of the application: + +nlbufsiz N +Netlink buffer size. A buffer of the specified size N is allocated for every +netlink group that is used. Please note that due to restrictions of the kernel +memory allocator, we cannot have a buffer size > 128kBytes. Larger buffer +sizes increase the performance, since less kernel/userspace context switches +are needed for the same amount of packets. The backside of this performance +gain is a potentially larger delay. The default value is 4096 bytes, which is +quite small. +flushtimeout N +The flushtimeout determines, after how many clock ticks (on alpha: 1ms, on +x86 and most other platforms: 10ms time units) the buffer/queue is to be +flushed, even if it is not full. This can be used to have the advantage of a +large buffer, but still a finite maximum delay introduced. The default value +is set to 10 seconds. + +Example: + +modprobe ipt_ULOG nlbufsiz=65535 flushtimeout=100 + +This would use a buffer size of 64k and a flushtimeout of 100 clockticks (1 second on x86). + +ulogd +

+ulogd is what this is all about, so let's describe it's configuration... +ulogd configfile syntax reference +

+All configurable parameters of ulogd are in the configfile, typically located +at '/etc/ulogd.conf'. +

+The following configuration parameters are available: + +nlgroup +The netlink multicast group, which ulgogd should bind to. This is the same as +given with the '--ulog-nlgroup' option to iptables. +logfile +The main logfile, where ulogd reports any errors, warnings and other unexpected conditions. Apart from a regular filename, the following special values can be used; ``syslog'' to log via the unix syslog(3) mechanism. ``stdout'' to log to stdout. +loglevel +This specifies, how verbose the logging to logfile is. Currently defined +loglevels are: 1=debug information, 3=informational messages, 5=noticable +exceptional conditions, 7=error conditions, 8=fatal errors, program abort. +plugin +This option is followed by a filename of a ulogd plugin, which ulogd shold load +upon initialization. This option may appear more than once. +rmem +Size of the netlink socket receive memory. You should set this to at least the +size of the kernel buffer (nlbufsiz parameter of the ipt_ULOG module). Please +note that there is a maximum limit in /proc/sys/net/core/rmem_max which you +cannot exceed by increasing the ``rmem'' parameter. You may need to raise the +system-wide maximum limit before. +bufsize +Size of the receive buffer. You should set this to at least the socket receive buffer (rmem). + +ulogd commandline option reference +

+Apart from the configfile, there are a couple of commandline options to ulogd: + +-h --help +Print a help message about the commandline options. +-V --version +Print version information about ulogd. +-d --daemon +For off into daemon mode. Unless you are debugging, you will want to use this +most of the time. +-c --configfile +Using this commandline option, an alternate config file can be used. This is +important if multiple instances of ulogd are to be run on a single machine. + + +Available plugins +

+It is important to understand that ulogd without plugins does nothing. It will receive packets, and do nothing with them. +

+There are two kinds of plugins, interpreter and output plugins. Interpreter +plugins parse the packet, output plugins write the interpreted information to +some logfile/database/... + +Interpreter plugins +

+ulogd comes with the following interpreter plugins: +ulogd_BASE.so +

+Basic interpreter plugin for nfmark, timestamp, mac address, ip header, tcp +header, udp header, icmp header, ah/esp header... Most people will want to load +this very important plugin. +ulogd_PWSNIFF.so +

+Example interpreter plugin to log plaintext passwords as used with FTP and +POP3. Don't blame me for writing this plugin! The protocols are inherently +insecure, and there are a lot of other tools for sniffing passwords... it's +just an example. +ulogd_LOCAL.so +

+This is a 'virtual interpreter'. It doesn't really return any information on +the packet itself, rather the local system time and hostname. Please note that +the time is the time at the time of logging, not the packets receive time. + +Output plugins +

+ulogd comes with the following output plugins: + +ulogd_OPRINT.so +

+A very simple output module, dumping all packets in the format + +===>PACKET BOUNDARY +key=value +key=value +... +===>PACKET BOUNDARY +... + +to a file. The only useful application is debugging. +

The module defines the following configuration directives: + +dumpfile +The filename where it should log to. The default is +/var/log/ulogd.pktlog + + +ulogd_LOGEMU.so +

+An output module which tries to emulate the old syslog-based LOG targed as far +as possible. Logging is done to a seperate textfile instead of syslog, though. +

+The module defines the following configuration directives: + +fileThe filename where it should log to. The default is +/var/log/ulogd.syslogemu +syncSet this to 1 if you want to have your logfile written +synchronously. This may reduce performance, but makes your log-lines appear +immediately. The default is 0 + + +ulogd_MYSQL.so +

+An output plugin for logging into a mysql database. This is only compiled if +you have the mysql libraries installed, and the configure script was able to +detect them. (that is: --with-mysql was specified for ./configure) + +

+The plugin automagically inserts the data into the configured table; It +connects to mysql during the startup phase of ulogd and obtains a list of the +columns in the table. Then it tries to resolve the column names against keys of +interpreter plugins. This way you can easily select which information you want +to log - just by the layout of the table. + +

+If, for example, your table contains a field called 'ip_saddr', ulogd will +resolve this against the key 'ip.saddr' and put the ip address as 32bit +unsigned integer into the table. + +

+You may want to have a look at the file 'doc/mysql.table' as an +example table including fields to log all keys from ulogd_BASE.so. Just delete +the fields you are not interested in, and create the table. + +

+The module defines the following configuration directives: + +table +Name of the table to which ulogd should log. +ldb +Name of the mysql database. +host +Name of the mysql database host. +port +TCP port number of mysql database server. +user +Name of the mysql user. +pass +Password for mysql. + + +ulogd_PGSQL.so +

+An output plugin for logging into a postgresql database. This is only compiled +if you have the mysql libraries installed, and the configure script was able to +detect them. (that is: --with-pgsql was specified for ./configure) + +

+The plugin automagically inserts the data into the configured table; It +connects to pgsql during the startup phase of ulogd and obtains a list of the +columns in the table. Then it tries to resolve the column names against keys of +interpreter plugins. This way you can easily select which information you want +to log - just by the layout of the table. + +

+If, for example, your table contains a field called 'ip_saddr', ulogd will +resolve this against the key 'ip.saddr' and put the ip address as 32bit +unsigned integer into the table. + +

+You may want to have a look at the file 'doc/mysql.table' as an +example table including fields to log all keys from ulogd_BASE.so. Just delete +the fields you are not interested in, and create the table. + +

+The module defines the following configuration directives: + +table +Name of the table to which ulogd should log. +db +Name of the database. +host +Name of the mysql database host. +port +TCP port number of database server. +user +Name of the sql user. +pass +Password for sql user. + + +ulogd_PCAP.so +

+An output plugin that can be used to generate libpcap-style packet logfiles. +This can be useful for later analysing the packet log with tools like tcpdump +or ethereal. + +The module defines the following configuration directives: + +file +The filename where it should log to. The default is: +/var/log/ulogd.pcap +sync +Set this to 1 if you want to have your pcap logfile written +synchronously. This may reduce performance, but makes your packets appear +immediately in the file on disk. The default is 0 + + +ulogd_SQLITE3.so +

+An output plugin for logging into a SQLITE v3 database. This is only compiled +if you have the sqlite libraries installed, and the configure script was able to +detect them. (that is: --with-sqlite3 was specified for ./configure) + +

+The plugin automagically inserts the data into the configured table; It +opens the sqlite db during the startup phase of ulogd and obtains a list of the +columns in the table. Then it tries to resolve the column names against keys of +interpreter plugins. This way you can easily select which information you want +to log - just by the layout of the table. + +

+If, for example, your table contains a field called 'ip_saddr', ulogd will +resolve this against the key 'ip.saddr' and put the ip address as 32bit +unsigned integer into the table. + +

+You may want to have a look at the file 'doc/sqlite3.table' as an +example table including fields to log all keys from ulogd_BASE.so. Just delete +the fields you are not interested in, and create the table. + +

+The module defines the following configuration directives: + +table +Name of the table to which ulogd should log. +db +Name of the database. +buffer +Size of the sqlite buffer. + + + +ulogd_SYSLOG.so +

+An output plugin that really logs via syslogd. Lines will look exactly like printed with traditional LOG target. + +

+The module defines the following configuration directives: + +facility +The syslog facility (LOG_DAEMON, LOG_KERN, LOG_LOCAL0 .. LOG_LOCAL7, LOG_USER) +level +The syslog level (LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG) + + + + QUESTIONS / COMMENTS +

+All comments / questions / ... are appreciated. +

+Just drop me a note to laforge@gnumonks.org +

+Please note also that there is now a mailinglist, ulogd@lists.gnumonks.org. +You can subscribe at +. +

+The preferred method for reporting bugs is the netfilter bugzilla system, +available at . + +

diff --git a/doc/ulogd.txt b/doc/ulogd.txt new file mode 100644 index 0000000..db231dd --- /dev/null +++ b/doc/ulogd.txt @@ -0,0 +1,580 @@ + ULOGD - the Userspace Logging Daemon + Harald Welte + Revision $Revision: 5846 $, $Date: 2005-07-12 17:33:23 +0200 + (Tue, 12 Jul 2005) $ + + This is the documentation for ulogd, the Userspace logging daemon. + ulogd makes use of the Linux >= 2.4.x packet filter subsystem (ipta- + bles) and the ULOG target for iptables. + ______________________________________________________________________ + + Table of Contents + + + 1. DESIGN + 1.1 CONCEPT + 1.2 DETAILS + + 2. INSTALLATION + 2.1 Linux kernel + 2.2 ipt_ULOG from netfilter/iptables patch-o-matic + 2.3 ulogd + 2.3.1 Recompiling the source + 2.3.2 Using a precompiled package + + 3. Configuration + 3.1 iptables ULOG target + 3.1.1 Quick Setup + 3.1.2 ULOG target reference + 3.1.3 ipt_ULOG module parameters + 3.2 ulogd + 3.2.1 ulogd configfile syntax reference + 3.2.2 ulogd commandline option reference + + 4. Available plugins + 4.1 Interpreter plugins + 4.1.1 ulogd_BASE.so + 4.1.2 ulogd_PWSNIFF.so + 4.1.3 ulogd_LOCAL.so + 4.2 Output plugins + 4.2.1 ulogd_OPRINT.so + 4.2.2 ulogd_LOGEMU.so + 4.2.3 ulogd_MYSQL.so + 4.2.4 ulogd_PGSQL.so + 4.2.5 ulogd_PCAP.so + 4.2.6 ulogd_SQLITE3.so + 4.2.7 ulogd_SYSLOG.so + + 5. QUESTIONS / COMMENTS + + + ______________________________________________________________________ + + 1. DESIGN + + 1.1. CONCEPT + + I want to provide a flexible, almost universal logging daemon for my + netfilter ULOG target. It is not optimized in any way, the goal is to + keep as simple as possible. These are my thoughts about how the + architecture which is most capable of doing that: + + + Interpreter plugins + It should be possible to add plugins / runtime modules for new + protocols, etc. For example the standard logging daemon + provides source-ip, dest-ip, source-port, dest-port, etc. + Logging for various other protocols (GRE, IPsec, ...) may be + implemented as modules. + + + Output plugins + ... describe how and where to put the information gained by + logging plugins. The easiest way is to build a line per packet + and fprint it to a file. Some people might want to log into a + SQL database or want an output conforming to the intrusion + detection systems communication draft from the IETF. + + + + 1.2. DETAILS + + The major clue is providing a framework which is as flexible as + possible. Nobody knows what strange network protocols are out there + :) Flexibility depends on the communication between the output of the + logging plugins and input of the output plugins. + + Rusty advised me to use some kind of type-key-value triples, which is + in fact what I implemented. + + One issue is, of course, performance. Up to ulogd 0.3, ulogd did + several linked list iterations and about 30 malloc() calls _per + packet_. This changed with the new >= 0.9 revisions: + + o Not a single dynamic allocation in the core during runtime. + Everything is pre-allocated at start of ulogd to provide the + highest possible throughput. + + o Hash tables in addition to the linked lists. Linked lists are only + traversed if we really want to access each element of the list. + + + 2. INSTALLATION + + + 2.1. Linux kernel + + First you will need a recent 2.4.x kernel. If you have a kernel >= + 2.4.18-pre8, it already has the kernel support for ULOG (ipt_ULOG.o). + + If you have an older kernel version (between 2.4.0 and 2.4.18-pre6), + you can use the patch-o-matic system of netfilter/iptables, as + described in the following section. + + + 2.2. ipt_ULOG from netfilter/iptables patch-o-matic + + You only need to read this chapter if you have a 2.4.x kernel <= + 2.4.18-pre6. + + In order to put the ipt_ULOG module into your kernel source,you need + the latest iptables package, or even better: the latest CVS snapshot. + A description how to obtain this is provided on the netfilter homepage + . + + To run patch-o-matic, just type + + + make patch-o-matic + + + + in the userspace directory of netfilter CVS. + + + 2.3. ulogd + + 2.3.1. Recompiling the source + + Download the ulogd package from + and untar it. + + If you want to build ulogd with MySQL support, type './configure + --with-mysql'. You may also have to specify the path of the mysql + libraries using '--with-mysql=path'. To build ulogd without MySQL + support, just use './configure'. + + To compile and install the program, call 'make install'. + + + 2.3.2. Using a precompiled package + + I also provide a SRPM, which should compile on almost any rpm-based + distribution. It is available at + + + Just download the package and do the usual 'rpm --rebuild '. + + + 3. Configuration + + 3.1. iptables ULOG target + + 3.1.1. Quick Setup + + Just add rules using the ULOG target to your firewalling chain. A very + basic example: + + + iptables -A FORWARD -j ULOG --ulog-nlgroup 32 --ulog-prefix foo + + + + To increase logging performance, try to use the + + + --ulog-qthreshold N + + + + option (where 1 < N <= 50). The number you specify is the amount of + packets batched together in one multipart netlink message. If you set + this to 20, the kernel schedules ulogd only once every 20 packets. All + 20 packets are then processed by ulogd. This reduces the number of + context switches between kernel and userspace. + + Of course you can combine the ULOG target with the different netfilter + match modules. For a more detailed description, have a look at the + netfilter HOWTO's, available on the netfilter homepage. + + 3.1.2. ULOG target reference + + + --ulog-nlgroup N + The number of the netlink multicast group to which ULOG'ed + packets are sent. You will have to use the same group number in + the ULOG target and ulogd in order to make logging work. + + --ulog-cprange N + Copyrange. This works like the 'snaplen' parameter of tcpdump. + You can specify a number of bytes up to which the packet is + copied. If you say '40', you will receive the first fourty + bytes of every packet. Leave it to 0 + + --ulog-qthreshold N + Queue threshold. If a packet is matched by the iptables rule, + and already N packets are in the queue, the queue is flushed to + userspace. You can use this to implement a policy like: Use a + big queue in order to gain high performance, but still have + certain packets logged immediately to userspace. + + --ulog-prefix STRING + A string that is associated with every packet logged by this + rule. You can use this option to later tell from which rule the + packet was logged. + + + 3.1.3. ipt_ULOG module parameters + + The ipt_ULOG kernel module has a couple of module loadtime parameters + which can (and should) be tuned to accomodate the needs of the + application: + + nlbufsiz N + Netlink buffer size. A buffer of the specified size N is + allocated for every netlink group that is used. Please note + that due to restrictions of the kernel memory allocator, we + cannot have a buffer size > 128kBytes. Larger buffer sizes + increase the performance, since less kernel/userspace context + switches are needed for the same amount of packets. The + backside of this performance gain is a potentially larger delay. + The default value is 4096 bytes, which is quite small. + + flushtimeout N + The flushtimeout determines, after how many clock ticks (on + alpha: 1ms, on x86 and most other platforms: 10ms time units) + the buffer/queue is to be flushed, even if it is not full. This + can be used to have the advantage of a large buffer, but still a + finite maximum delay introduced. The default value is set to 10 + seconds. + + Example: + + + modprobe ipt_ULOG nlbufsiz=65535 flushtimeout=100 + + + + This would use a buffer size of 64k and a flushtimeout of 100 clock- + ticks (1 second on x86). + + + 3.2. ulogd + + ulogd is what this is all about, so let's describe it's + configuration... + + 3.2.1. ulogd configfile syntax reference + + All configurable parameters of ulogd are in the configfile, typically + located at '/etc/ulogd.conf'. + The following configuration parameters are available: + + nlgroup + The netlink multicast group, which ulgogd should bind to. This + is the same as given with the '--ulog-nlgroup' option to + iptables. + + logfile + The main logfile, where ulogd reports any errors, warnings and + other unexpected conditions. Apart from a regular filename, the + following special values can be used; ``syslog'' to log via the + unix syslog(3) mechanism. ``stdout'' to log to stdout. + + loglevel + This specifies, how verbose the logging to logfile is. Currently + defined loglevels are: 1=debug information, 3=informational + messages, 5=noticable exceptional conditions, 7=error + conditions, 8=fatal errors, program abort. + + plugin + This option is followed by a filename of a ulogd plugin, which + ulogd shold load upon initialization. This option may appear + more than once. + + rmem + Size of the netlink socket receive memory. You should set this + to at least the size of the kernel buffer (nlbufsiz parameter of + the ipt_ULOG module). Please note that there is a maximum limit + in /proc/sys/net/core/rmem_max which you cannot exceed by + increasing the ``rmem'' parameter. You may need to raise the + system-wide maximum limit before. + + bufsize + Size of the receive buffer. You should set this to at least the + socket receive buffer (rmem). + + 3.2.2. ulogd commandline option reference + + Apart from the configfile, there are a couple of commandline options + to ulogd: + + -h --help + Print a help message about the commandline options. + + -V --version + Print version information about ulogd. + + -d --daemon + For off into daemon mode. Unless you are debugging, you will + want to use this most of the time. + + -c --configfile + Using this commandline option, an alternate config file can be + used. This is important if multiple instances of ulogd are to + be run on a single machine. + + + 4. Available plugins + + It is important to understand that ulogd without plugins does nothing. + It will receive packets, and do nothing with them. + + There are two kinds of plugins, interpreter and output plugins. + Interpreter plugins parse the packet, output plugins write the + interpreted information to some logfile/database/... + + 4.1. Interpreter plugins + + ulogd comes with the following interpreter plugins: + + 4.1.1. ulogd_BASE.so + + Basic interpreter plugin for nfmark, timestamp, mac address, ip + header, tcp header, udp header, icmp header, ah/esp header... Most + people will want to load this very important plugin. + + 4.1.2. ulogd_PWSNIFF.so + + Example interpreter plugin to log plaintext passwords as used with FTP + and POP3. Don't blame me for writing this plugin! The protocols are + inherently insecure, and there are a lot of other tools for sniffing + passwords... it's just an example. + + 4.1.3. ulogd_LOCAL.so + + This is a 'virtual interpreter'. It doesn't really return any + information on the packet itself, rather the local system time and + hostname. Please note that the time is the time at the time of + logging, not the packets receive time. + + + 4.2. Output plugins + + ulogd comes with the following output plugins: + + + 4.2.1. ulogd_OPRINT.so + + A very simple output module, dumping all packets in the format + + + ===>PACKET BOUNDARY + key=value + key=value + ... + ===>PACKET BOUNDARY + ... + + + + to a file. The only useful application is debugging. + + The module defines the following configuration directives: + + dumpfile + The filename where it should log to. The default is + /var/log/ulogd.pktlog + + + 4.2.2. ulogd_LOGEMU.so + + An output module which tries to emulate the old syslog-based LOG + targed as far as possible. Logging is done to a seperate textfile + instead of syslog, though. + + The module defines the following configuration directives: + + file + The filename where it should log to. The default is + /var/log/ulogd.syslogemu + + sync + Set this to 1 if you want to have your logfile written + synchronously. This may reduce performance, but makes your log- + lines appear immediately. The default is 0 + + + 4.2.3. ulogd_MYSQL.so + + An output plugin for logging into a mysql database. This is only + compiled if you have the mysql libraries installed, and the configure + script was able to detect them. (that is: --with-mysql was specified + for ./configure) + + + The plugin automagically inserts the data into the configured table; + It connects to mysql during the startup phase of ulogd and obtains a + list of the columns in the table. Then it tries to resolve the column + names against keys of interpreter plugins. This way you can easily + select which information you want to log - just by the layout of the + table. + + + If, for example, your table contains a field called 'ip_saddr', ulogd + will resolve this against the key 'ip.saddr' and put the ip address as + 32bit unsigned integer into the table. + + + You may want to have a look at the file 'doc/mysql.table' as an + example table including fields to log all keys from ulogd_BASE.so. + Just delete the fields you are not interested in, and create the + table. + + + The module defines the following configuration directives: + + table + Name of the table to which ulogd should log. + + ldb + Name of the mysql database. + + host + Name of the mysql database host. + + port + TCP port number of mysql database server. + + user + Name of the mysql user. + + pass + Password for mysql. + + + 4.2.4. ulogd_PGSQL.so + + An output plugin for logging into a postgresql database. This is only + compiled if you have the mysql libraries installed, and the configure + script was able to detect them. (that is: --with-pgsql was specified + for ./configure) + + + The plugin automagically inserts the data into the configured table; + It connects to pgsql during the startup phase of ulogd and obtains a + list of the columns in the table. Then it tries to resolve the column + names against keys of interpreter plugins. This way you can easily + select which information you want to log - just by the layout of the + table. + + + If, for example, your table contains a field called 'ip_saddr', ulogd + will resolve this against the key 'ip.saddr' and put the ip address as + 32bit unsigned integer into the table. + + + You may want to have a look at the file 'doc/mysql.table' as an + example table including fields to log all keys from ulogd_BASE.so. + Just delete the fields you are not interested in, and create the + table. + + + The module defines the following configuration directives: + + table + Name of the table to which ulogd should log. + + db Name of the database. + + host + Name of the mysql database host. + + port + TCP port number of database server. + + user + Name of the sql user. + + pass + Password for sql user. + + + 4.2.5. ulogd_PCAP.so + + An output plugin that can be used to generate libpcap-style packet + logfiles. This can be useful for later analysing the packet log with + tools like tcpdump or ethereal. + + The module defines the following configuration directives: + + file + The filename where it should log to. The default is: + /var/log/ulogd.pcap + + sync + Set this to 1 if you want to have your pcap logfile written + synchronously. This may reduce performance, but makes your + packets appear immediately in the file on disk. The default is + 0 + + + 4.2.6. ulogd_SQLITE3.so + + An output plugin for logging into a SQLITE v3 database. This is only + compiled if you have the sqlite libraries installed, and the configure + script was able to detect them. (that is: --with-sqlite3 was specified + for ./configure) + + + The plugin automagically inserts the data into the configured table; + It opens the sqlite db during the startup phase of ulogd and obtains a + list of the columns in the table. Then it tries to resolve the column + names against keys of interpreter plugins. This way you can easily + select which information you want to log - just by the layout of the + table. + + + If, for example, your table contains a field called 'ip_saddr', ulogd + will resolve this against the key 'ip.saddr' and put the ip address as + 32bit unsigned integer into the table. + + + You may want to have a look at the file 'doc/sqlite3.table' as an + example table including fields to log all keys from ulogd_BASE.so. + Just delete the fields you are not interested in, and create the + table. + + + The module defines the following configuration directives: + + table + Name of the table to which ulogd should log. + + db Name of the database. + + buffer + Size of the sqlite buffer. + + 4.2.7. ulogd_SYSLOG.so + + An output plugin that really logs via syslogd. Lines will look exactly + like printed with traditional LOG target. + + + The module defines the following configuration directives: + + facility + The syslog facility (LOG_DAEMON, LOG_KERN, LOG_LOCAL0 .. + LOG_LOCAL7, LOG_USER) + + level + The syslog level (LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, + LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG) + + 5. QUESTIONS / COMMENTS + + All comments / questions / ... are appreciated. + + Just drop me a note to laforge@gnumonks.org + + Please note also that there is now a mailinglist, + ulogd@lists.gnumonks.org. You can subscribe at + . + + + The preferred method for reporting bugs is the netfilter bugzilla + system, available at . + + + diff --git a/drl.xml b/drl.xml new file mode 100644 index 0000000..3b3f4b6 --- /dev/null +++ b/drl.xml @@ -0,0 +1,6 @@ + + + + 127.0.0.1 + + diff --git a/drl/DRL-LICENSE b/drl/DRL-LICENSE new file mode 100644 index 0000000..52a717c --- /dev/null +++ b/drl/DRL-LICENSE @@ -0,0 +1,28 @@ +Copyright 2008 The Regents of the University of California All Rights Reserved + +Permission to use, copy, modify and distribute any part of this Distributed +Rate Limiting program for educational, research and non-profit purposes, +without fee, and without a written agreement is hereby granted, provided +that the above copyright notice, this paragraph and the following three +paragraphs appear in all copies. + +Those desiring to incorporate Distributed Rate Limiting into commercial +products or use for commercial purposes should contact the Technology Transfer +& Intellectual Property Services, University of California, San Diego, 9500 +Gilman Drive, Mail Code 0910, La Jolla, CA 92093-0910, Ph: (858) 534-5815, +FAX: (858) 534-7345, E-MAIL:invent@ucsd.edu . + +IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR +DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING +LOST PROFITS, ARISING OUT OF THE USE OF THIS Distributed Rate Limiting, EVEN +IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +THE Distributed Rate Limiting PROVIDED HEREIN IS ON AN "AS IS" BASIS, AND THE +UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, +UPDATES, ENHANCEMENTS, OR MODIFICATIONS. THE UNIVERSITY OF CALIFORNIA MAKES +NO REPRESENTATIONS AND EXTENDS NO WARRANTIES OF ANY KIND, EITHER IMPLIED OR +EXPRESS, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF +Distributed Rate Limiting WILL NOT INFRINGE ANY PATENT, TRADEMARK OR OTHER +RIGHTS. diff --git a/drl/Doxyfile b/drl/Doxyfile new file mode 100644 index 0000000..ac38ba6 --- /dev/null +++ b/drl/Doxyfile @@ -0,0 +1,1252 @@ +# Doxyfile 1.5.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = ulogd_DRL + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 0.0 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = Documentation + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, +# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, +# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, +# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# This tag can be used to specify the encoding used in the generated output. +# The encoding is not always determined by the language that is chosen, +# but also whether or not the output is meant for Windows or non-Windows users. +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES +# forces the Windows encoding (this is the default for the Windows binary), +# whereas setting the tag to NO uses a Unix-style encoding (the default for +# all platforms other than Windows). + +USE_WINDOWS_ENCODING = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to +# include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from the +# version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = calendar.h comm/drl_state.c comm/drl_state.h comm/peer_comm.c comm/peer_comm.h config.c config.h estimate.c logging.c logging.h rate_accounting/common_accounting.h rate_accounting/samplehold.c rate_accounting/samplehold.h rate_accounting/simple.c rate_accounting/simple.h rate_accounting/standard.c rate_accounting/standard.h raterouter.h ratetypes.h ulogd_DRL.c util.c util.h + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentstion. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a caller dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that a graph may be further truncated if the graph's +# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH +# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), +# the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, which results in a white background. +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/drl/Makefile.in b/drl/Makefile.in new file mode 100644 index 0000000..0d1b6ec --- /dev/null +++ b/drl/Makefile.in @@ -0,0 +1,31 @@ +# +include @top_srcdir@/Rules.make + +CFLAGS+=-I@top_srcdir@ -I@top_srcdir@/libipulog/include -I@top_srcdir@/include `xml2-config --cflags` +SH_CFLAGS:=$(CFLAGS) -fPIC + +# Normally You should not need to change anything below +# + +SHARED_LIBS=ulogd_DRL.so +OBJECTS=config.o drl_state.o estimate.o logging.o peer_comm.o samplehold.o simple.o standard.o ulogd_DRL.o util.o + +all: $(SHARED_LIBS) + +distrib: + +$(SHARED_LIBS): $(OBJECTS) + $(LD) $(LDFLAGS) -shared -o $@ $(OBJECTS) -lc + +%.o: %.c + $(CC) $(CFLAGS) -c $< + +clean: + $(RM) $(SHARED_LIBS) *.o + +distclean: + $(RM) Makefile + +install: all + $(INSTALL) -m 755 -d $(DESTDIR)$(ULOGD_LIB_PATH) + $(INSTALL) -m 755 *.so $(DESTDIR)$(ULOGD_LIB_PATH) diff --git a/drl/Manual.txt b/drl/Manual.txt new file mode 100644 index 0000000..bf25060 --- /dev/null +++ b/drl/Manual.txt @@ -0,0 +1,128 @@ +--DRL manual-- + +DRL employs two principal abstractions, limiters and identities. + +An identity is a group of nodes that are cooperating to enforce a rate limit. +At any given node, an identity structure consists of a rate limit, a flow +accounting table, a list of neighboring nodes, and other accounting +information. Our implementation currently supports two types of identities. +"Machine" identities limit the outgoing rate of all traffic leaving a machine, +regardless of the traffic's sender. "Set" identities limit the outgoing rate +of some subset of the traffic leaving a machine. Sets can contain other sets +as well as leaves (which correspond to slivers in PlanetLab). + +A limiter is an entity which contains (and schedules) identities, attributes +packets to identities, and sends and receives messages to other limiters on +behalf of identities. Typically, there will be only one limiter per node, +and it will be responsible for one or more identities. + +-Implementation and configuration- + +ulogd_DRL is a plugin for ulogd, the Linux userspace packet logging daemon. +Using DRL requires that two configuration files be configured appropriately. +The first file is ulogd's configuration file. Ulogd has a number of +configuration options that are not relevant to DRL, and an explanation of those +can be found in the ulogd documentation. The DRL sections of the ulogd config +file are as follows: + +The ulogd_DRL.so plugin must be loaded. This is accomplished with a line such +as: + +plugin="/usr/lib/ulogd/ulogd_DRL.so" + +where /usr/lib/ulogd/ is the path of your ulogd plugin directory. After the +"plugin" line, the following parameters must be present: + +[DRL] +nodelimit=0 +policy=FPS +estintms=500 +drl_logfile="/root/pl1-log" +drl_loglevel 2 +drl_configfile="/root/config.xml" + +nodelimit specifies a static limit on the amount of network traffic that can be +sent by the node (megabits/sec). NOTE: Set this to 0 for unlimited. + +policy specifies the enforcement policy. Valid options are GRD and FPS. GRD +is currently broken, so use FPS for now. + +estintms is the estimate interval. This specifies the time interval at which +DRL can schedule identity updates. Lower values give better responsiveness but +incur higher overhead. NOTE: this is in milliseconds. + +drl_logfile specifies where the drl logfile should be written. + +drl_loglevel specifies the verbosity of logging. 1 - Debug, 2 - Warn, +3 - Critical + +drl_configfile specifies the location of the second, DRL-only configuration +file. + +The second file (whose location is determined by drl_configfile) is an XML file +containing a series of DRL identity specifications. DRL supports two types of +identities. 1) machine identities: A machine identity is responsible for +limiting all traffic that leaves a machine, regardless of the traffic's sliver +of origin. 2) set identities: A set identity is responsible for limiting the +traffic from a set of slivers or other set identities. + +The following is an example DRL configuration file: + + + + + 137.110.222.242 + 137.110.222.243 + + + 137.110.222.240 + 1f9 + + + 137.110.222.245 + 1fa + 20 + + + +This file creates one machine identity and two set identities. The resulting +hierarchy would look like this, where 1f9 and 1fa are slivers: + + 11 + | + 21 + / \ + 20 1fa + | + 1f9 + +With each identity specifier, the following fields must be defined: + +id is a globally unique identifier for the identity. + +limit is the identity's rate limit (in megabits per second). + +commfabric specifies the way in which the identity communicates with its peers. +Valid options are MESH and GOSSIP. If GOSSIP is select, the branch field must +be present and positive. + +branch specifies the number of peers to which a message should be sent during +each estimate interval. Note that this field is ignored when commfabric is +MESH. + +accounting specifies the packet accounting mechanism. Just leave this as +STANDARD for now, or bad things might happen. :) + +ewma determines the extent to which rate changes are smoothed using rate +history information. 0.1 is generally a good value. + +intervals specifies the number of estimate intervals (defined in the ulogd +config file) to wait between updates. For example, if the estimate interval is +500ms and an identity sets intervals to 2, the identity will be scheduled for +updates once every second. + +Each identity must also have one or more peers. Peers are listed within +tags inside the identity specifier. In addition to peers, set identities must +also have at least one or tag. tags refer to slice ids for +slices that are available at the local node. tags refer to the globally +unique id of another set identity. diff --git a/drl/README b/drl/README new file mode 100644 index 0000000..ec0139d --- /dev/null +++ b/drl/README @@ -0,0 +1,637 @@ +2-20-08 + +Use this to capture the rates from the individual slices. + + while true; do /sbin/tc -s class show dev eth0 | grep -A 3 11f8 | grep -A + 1 "class htb" | grep Sent | cut -d " " -f 3; sleep 1; done > GRD_pl_drl_34 + + + + + +2-15-08 + +Damn sysnet33 db won't come up. says /tmp is full in the chroot +myplc/plc/root/var/log/pglog, but it's not full. +So I'm trying to replace the loopback filesystem with something clean from +the RPM. +using cpio --no-absolute-filenames +And +rpm2cpio | cpio -diu +but u is don't prompt. so I'll issue +rpm2cpio | cpio -di --no-absolute_filenames + +OK, did this, then I copied over root.img to where I have it installed. +And it all worked! Sweet. The image is mostly independent of the data! + + + + + + +ADDING A PL NODE +1.) turn off crond for restarting ulogd +in pl_netflow:/etc/crond.d/netflow +edited the line that calls init.d/netflow restart +because I don't want it to keep restarting ulogd as I test it. +2.) Allow pl_netflow to run tc +I am also changing the pl_netflow.conf in /etc/vservers/pl_netflow.conf +So that S_CAPS="CAP_NET_ADMIN" +Then, from the root slice, vserver pl_netflow restart. +3.) copy over the ./start script from the pl_netflow /root directory. +4.) put bwlimit_drl.py into /usr/share/util-vserver/bwlimit2.py on the root +slice +put bwlimit_drl.py into /usr/share/util-vserver/bwlimit_drl.py on the +pl_netflow slice. +Future, make the names consistent +5.) pull the sch_netem.ko over and insmod it. + +cd /lib/modules/2.6.12-1.1398_FC4.5.planetlab/kernel/net/sched/ +[root@sysnet32 sched]# scp -i ~/.ssh/root_ssh_key.rsa root@sysnet34:/lib/modules/2.6.12-1.1398_FC4.5.planetlab/kernel/net/sched/sch_netem_plab.ko . +insmod sch_netem_plab.ko + +6.) [root@vserver:pl_netflow ~]/etc/init.d/ulogd stop +7.) vserver pl_netflow enter +8.) copy over ulogd. run ./start +9.) Edit the ulogd configuration script. + + +2-12-08 + +bwlimit.py cannot look up the slice names in the pl_netflow slice b/c there +are not entries in the /etc/passwd file for the slices. Of course there +aren't. Even ulogd_NETFLOW.c replaces /etc/passwd with /dev/null. + +so in the short term I will copy over the roots /etc/passwd and place it +where the new bwlimit_drl exists. /usr/share/util-vserver/passwd_drl +I can have the root periodically copy this file into the pl_netflow slice +in a cron job, or whenever a new slice is created. + +This is a hack. There are probably better ways, but it's a moving target. +Now hack bwlimit_drl to use that file to look up slice contexts. + + + +HTB DOCS http://luxik.cdi.cz/~devik/qos/htb/manual/userg.htm + +2-10-08 + +We probably have to put the netem at the bottom of the tbf. If we put it +in the middle, say off of the 1:10 class, then we need to direct all +traffic that would have been directed to a lower class in the htb to the +1:10 class. Then the traffic has to be directed to the lower classes and +be accounted for directly. This screws with how traffic classification is +done; I don't even know if it will obey the tb appropriately either, since +the best you can do is put another htb qdisc below the netem class. And +there is no way to directly have that qdisc borrow from the "parent" one +that's just been terminated by the netem qdisc. Got that? + + + + + + +2-7-08 + +Screwing around with all the kernel configs has forced the build process to +rebuild all the kernels. blech. + + +BUILDING NETEM for plab machines: +Kevin made an ubunto chroot install on his linux machine and built 3.3 gcc +in it, and then copied over the source linux tree that had the .config +stolen from sysnet34 /proc/config.gz. We also had to change the magic +string so that it believed it was bulit to fc 4.5, not 4.7. +Use insmod +/lib/modules/2.6.12-1.1398_FC4.5.planetlab/kernel/net/sched/sch_netem_plab.ko + + +see sysnet35:/root/myplc/build/SOURCES/CRAP/linux-2.6.12/.config + + +We added a node at the root qdisc and it succesfully appears to delay +packets. So now let's figure out how to add it to the bwlimit.py code so +that it is always present and can be tweaked (replaced) when running +ulogd. + +---- +tc qdisc del dev eth0 root handle 1: +tc qdisc add dev eth0 parent 1: handle 2: htb default 1fff +And everything then falls out of 2: + +But this will netem everything out of hte host, leaving nothing for +"exempt" slices like the root. Not what we want. + +We place a netem qdisc at the leaf of every non-exempt slice traffic class +in the HTB. + +2-5-08 + +in pl_netflow vserver +/etc/cron.d/netflow keeps restarting netflow init.d script which keeps +restarting ulogd if started by hand. Fucking buggy. + +in root vserver +see pl_mom cron job +which runs bwmon and pl_mop. pl_mop makes sure pl_netflow is running. + +!!!!!!!!!! +in sysnet34 pl_netflow:/etc/crond.d/netflow +edited the line that calls init.d/netflow restart +because I don't want it to keep restarting ulogd as I test it. +!!!!! +I am also changing the pl_netflow.conf in /etc/vservers/pl_netflow.conf +So that S_CAPS="CAP_NET_ADMIN" +Then, from the root slice, vserver pl_netflow restart. + + then parent ceil, looks like no borrowing occurs +unless the cburst is very low. if you set cburst to 0, then tc sets cburst +to something that allows the class to reach its ceiling. + + + +HOWTO: Set a ceiling on a particular slice. +/usr/share/util-vaserver/bwlimit.py on pl_drl 1 8bit 500kbit 8bit 1gib +The first arg is share. Works in the way you expect. +The next is min guaranteed. The next is max or ceiling. This is the one +to set. The next two are min/ceiling for special destinations. + +HOWTO: Set a ceiling on all slices leaving a node. +1.) We can change the ceiling for the 1:10 subclass. +this should limit all traffic for all slices to non-exempted destinations + + /sbin/tc class replace dev eth0 parent 1:1 classid 1:10 htb rate 8bit ceil 500kbit +This does not work. + +2.) We can change the ceiling for the 1:1 root class. + + /sbin/tc class replace dev eth0 parent 1: classid 1:1 htb rate 500kbit +modified this to + /sbin/tc class replace dev eth0 parent 1: classid 1:1 htb rate 8bit ceil 500kbit +With no effect. + +Mucking with classid 1:1 seems to make the machine very unhappy. + + +bwlimit seems to set the bottom classes ceilings to the ceiling of the 1:10 +block. Then why have the 1:10 block? + + + +Do 1&2, and neither have any effect. + +It looks like only the bottom most class has any affect. If I re-init the +bwlimit.py script, then a rule parent 1:10 leaf 1:1fff seems to get all the +traffic. And it is the limit that seems to matter. + +I see. 1fff is the deafult_xid. So when something has not been caught +earlier this is where it goes to be limited and caught. + + +tcp netperf tests for rate limiting from a slice. +Experiment with 34->35. Logged in to the pl_drl slice to issue the +netperf. + +vserver pl_drl status +vserver pl_drl_two status + +vservers aren't running until you log in to them. so the above command +won't return something useful until that point. + + + +12-18-08 + +/etc/init.d/ncsd restart or reload (caches ldap information) this is for +the sysnet machines. + + +The files that you care about are in the release. they are +/usr/share/util-vaserver/bwlimit.py +This is what makes the calls to TC to do the traffic control. + + + +OK: Logging in to the drl slice, and setting up the netperf +server/client. +ssh -i ~/.ssh/myplc_admin.rsa -l pl_drl sysnet34.ucsd.edu + +So I'm sending netperf outbound flows from the pl_drl slice +and it is getting recorded in the class htb 1:11f8 (which is context 504). +When you do a vserver list, though, it says there's only a 503 (though when +you log in to 503, it says the "security context" is 504). + + + 1111 /usr/share/util-vserver/bwlimit.py -d eth0 -v init + 1115 /usr/share/util-vserver/bwlimit.py -d eth0 on pl_drl 1 1kbit 10kbit 1kbit 10kbit + + +11-14-07 + + +planetlab website login +kyocum@cs.ucsd.edu +ate smurfs as well +sysnet35 kyocum - big Dog - and killing name root + + +symlink cvs source code to a ulogd/drl directory. + +for file in '*.h'; do echo $file; rm /root/myplc/ulogd/drl/$file ; done +for file in '*.c'; do echo $file; ln -s /root/ratelimiting/myplc/$file /root/myplc/ulogd/drl/. ; done + + +11-11-07 + +Brought back 32 and 33 from power offs. 32 is mounting everything read +only. 34 is working fine, but it was never powered off. + + + +10-29-07 +Back from NSDI, SOSP, Texas, and firestorm. Will modify ulogd to perform +DRL. Will first use GRD, as we can drop based on simple probabilities. +Though we should be able to see all the packets that are coming in to the +machine using ulogd. + + + + +9-16-07 + +vserver pl_netflow enter +scp root@sysnet35:~/myplc/build/RPMS/i386/ulogd-1.02-11.i386.rpm . + +Where does the output go? + + +9-14-07 #2 + +Now let's try to install the ulog srpm that was created on one of the myplc +nodes. + +sysnet32,34: myplc nodes +sysnet35: build box +sysnet33: myplc controller + +On 34, entering vserver for ulogd, downloading srpm, and trying to +install. + +/etc/rc.d/init.d/ulogd stop +rpm -e --nodeps ulogd +rpm -Uvh ulogd-1.02-11.i386.rpm +/etc/rc.d/init.d/ulogd start + + +9-14-07 + +Have installed FC4 on sysnet35. Am following Marc's instructions in his email.Check out rc1 build and rc1 ulogd. +OK, I'm trying to build things using marc's instructions and not the entire +myplc build envi +ronment that is in the GUIDE. I'll try that next. +Ok, I've set it all up. I'm using +mirrors.kernel.org +and fedora/core/4/os +-- +Ok, now I'm about to cd into build and make ulogd . . . +q + +xPWD=$PWD +cvs -d :pserver:anonymous@cvs.planet-lab.org:/cvs co -r planetlab-4_1-rc1 +build +cvs -d :pserver:anonymous@cvs.planet-lab.org:/cvs co -r planetlab-4_1-rc1 +ulogd +cd build +mkdir SPEC SOURCES +cd SPEC +# note that you will need these symlinks to use the full paths --- NOT +relative paths +# which is why I am using $xPWD +ln -fs $xPWD/ulogd/ulogd.spec ulogd.spec +cd ../SOURCES +ln -fs $xPWD/ulogd ulogd +cd .. +make ulogd + +Assuming the dependencies are set up right, this should first suck down the +kernel and mysql modules via CVS, build them (which may take some time), +and then build ulogd. + +Success!!!!! + +Now, check out ratelimiting but add root to cvs group number 30008 +groupadd -g 30008 cvs (add group def) + + +8-17-07 + +Made two slices. pl_drl_one and pl_drl_two +to log in to the slices I uploaded a key, myplc_admin.{rsa,pub} + +sake:~/.ssh grant$ ssh -i myplc_admin.rsa -l pl_drl_one sysnet34 + + +We want to modify ULOGD + +can't run it. root@sysnet34 sbin]# ./ulogd --help +./ulogd: error while loading shared libraries: libproper.so.0: cannot open +shared object file: No such file or directory + +trying chroot to the netflow slice first. +That seems to do the trick. + +bash-3.00# ./ulogd +Fri Aug 17 20:05:08 2007 <3> ulogd.c:300 registering interpreter `raw' +Fri Aug 17 20:05:08 2007 <3> ulogd.c:300 registering interpreter `oob' +Fri Aug 17 20:05:08 2007 <3> ulogd.c:300 registering interpreter `ip' +Fri Aug 17 20:05:08 2007 <3> ulogd.c:300 registering interpreter `tcp' +Fri Aug 17 20:05:08 2007 <3> ulogd.c:300 registering interpreter `icmp' +Fri Aug 17 20:05:08 2007 <3> ulogd.c:300 registering interpreter `udp' +Fri Aug 17 20:05:08 2007 <3> ulogd.c:300 registering interpreter `ahesp' +Fri Aug 17 20:05:08 2007 <3> ulogd.c:300 registering interpreter `gre' +Fri Aug 17 20:05:08 2007 <5> ulogd.c:355 registering output `netflow' +ERROR: Unable to create netlink socket: Bad file descriptor +8-21-07 + +get yum to work on sysnet34. +in /etc/yum.conf, changed reposdir=/etc/yum.repos.d/ +http://onelab-build.inria.fr/websvn/filedetails.php?repname=OneLab&path=%2Fnew_plc_www%2Ftrunk%2FPlanetLabConf%2Fyum.conf.php +has a crazy yum.conf file. +yum install cvs +yum install gcc + +[root@sysnet34 2.6.12-1.1398_FC4.5.planetlab]# cd /usr/src/ +[root@sysnet34 src]# mkdir kernels + +Install the kernel source the lib/modules directory symlinks to +/usr/src/kernels/ +where we place 2.6.12-1.1398_FC4.5.planetlab + +Checkout kernel: +cvs co -r planetlab-4_1-rc1 linux-2.6 +placed in /usr/src/kernels/ + +Building PLAB kernel: + +fuck yum, no ncurses devel, no yum supository. +wget http://coblitz.planet-lab.org/pub/fedora/linux/core/updates/4/x86_64/ncurses-devel-5.4-19.fc4.i386.rpm +rpm -i ncurses---- + +OK, now the stupid make menuconfig worked, but we're going to copy a kernel +config from /proc/config.gz +zcat config.gz > /root/kernels/linux-2.6/.config +make O=/root/kernels/linux-2.6/build/ oldconfig + +So none of that worked, copy config to .config in top level directory. +then run menuconfig, then save config, then compile. that works. + +Yay! + +./build/include/linux/version.h +so config that shit. + +Configuring ulogd +./configure --with-kernel=/root/kernels/linux-2.6/build/ +config success! + +download RPM and install from location above. +mysql-devel-4.1.20-1.FC4.1.x86_64.rpm +rpm -i <> + +Ok, had to re-enable yum.conf to use yum.repos.d +had to modify yum.repos.d/fedora-devel so that it wasn't used. +then I could yum install openssl-devel and mysql-devel + +The linker is bitching about mysql objects not being present. +trying yum install mysql.i386 +already installed trying +yum install ulogd-pgsql.i386 +yum install ulogd-mysql.i386 +yum install mysqlclient10-devel.i386 + +Ok, all that is shit. Marc sent me a yumrepos.tgz that is on my +desktop. I put all the files in the right place on 34. He then sent me a +yum install line that is this. + +yum -y install beecrypt-devel bzip2 coreutils cpio createrepo curl +curl-devel cvs db4-devel dev diffutils dnsmasq docbook-utils-pdf dosfstools +doxygen expect gcc-c++ gd glibc glibc-common gnupg gperf gzip httpd install +iptables less libpcap libpcap-devel libtool linuxdoc-tools mailx make +metadata mkisofs mod_python mod_ssl mysql mysql-devel mysql-server nasm +ncurses-devel openssh openssl php php-devel php-gd php-pgsql postgresql +postgresql-devel postgresql-python postgresql-server python python-devel +PyXML readline-devel redhat-rpm-config rpm rpm-build rpm-devel rsync +sendmail sendmail-cf sharutils sudo tar tetex-latex time vconfig vixie-cron +wget xmlsec1 xmlsec1-openssl yum + +which should make the box a build box. + +Of course, what I should really be doing is making a fresh FC4 node as my +build environment, but whatever. + + +------ + +Ok, trying to figure out if there is a way to "start" the pl_netflow +vserver. Don't know if it's currently running. Perhaps it is. +vserver-stat shows 4 vservers, besides the root context, 0. +#503 is pl_netflow. The other two are the two drl slices. +Each vserver has a configuration file shown here: +[root@sysnet34 sbin]# more /etc/vservers/pl_netflow.conf + +To enter a vserver context you can say +vserver enter + +To run ulogd + +vserver pl_netflow enter +cd /usr/sbin +./ulogd + +The configuration file is in +/etc/ulogd.conf +/var/log/ulogd.log + + + + +8-07 +Installing myPLC. Trying to build rate limiting infrastructure on top of +it. + + +sysnet33. has only mounted /dev/xen_vg/dom0 on / +that is only 2GB. There is another LVM called /dev/xen_vg/lvol0. +It has 10GB. We will try to mount that. +Display with lvmdisplay + +The underlying disk partition is /dev/sda3 (physical volume) +display pv's with pvdisplay + +adding line in /etc/fstab to mount lvol0 on /lvol0 +This partition has plenty of space. Everything looks good. + +use linux authconfig to see if it's using ldap for user authentication +to disable selinux +http://www.crypt.gen.nz/selinux/disable_selinux.html +It was already disabled, see /etc/selinux/config +INSTALLED in /lvol0 +I edited /lvol0/myplc/etc/sysconfig/plc +I symlinked /etc/init.d/plc --> installed +I symlinked /etc/sysconfig/plc --> installed + +I edited etc/sysconfig/plc to point to my installation in /lvol0/myplc + +root@localhost.localdomain +made a new account as well. +kyocum@cs.ucsd.edu +8smurf2 + +--- + +Trying to install the images for the new nodes. They are in /lvol0/myplc/plc/root/data/var/www/html/download + +on sysnet33, +yum install mkisofs +./bootcustom.sh DRL.iso plnode34.txt + + +--- + +Machines come up in debug mode. They have insufficient resources. +Probably disk space. Need to modify the boot script that is sent over +from myplc (beckerr), or we can add a "/minhw" to the node type in the +controller. The boot program is at: + +-bash-3.00$ pwd +/lvol0/myplc/plc/data/var/www/html/boot/bootmanager.sh +nope just contains binary of bootmanager. +/lvol0/myplc/plc/root/etc/plc.d/bootmanager is where it's at. nope. +qq/usr/share/bootmanager/ + + +Generally, running BootManager by hand is the standard procedure. Set the +machine to "Boot" state via your PLC API or web server. When the machine +sfails +to boot, hit Ctrl-C, login as root/root, cd /tmp/source, and run +"./BootManager.py". Figure out where it dies, then start adding prints in +the +appropriate places to figure out why. + + + diff --git a/drl/bsd_queue.h b/drl/bsd_queue.h new file mode 100644 index 0000000..74cafac --- /dev/null +++ b/drl/bsd_queue.h @@ -0,0 +1,627 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD: src/sys/sys/queue.h,v 1.69 2008/05/22 14:40:03 ed Exp $ + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +#include + +/* + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - - - + + * _LAST - - + + + * _FOREACH + + + + + * _FOREACH_SAFE + + + + + * _FOREACH_REVERSE - - - + + * _FOREACH_REVERSE_SAFE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _CONCAT - - + + + * _REMOVE_HEAD + - + - + * _REMOVE_NEXT + - + - + * _REMOVE + + + + + * + */ +#ifdef QUEUE_MACRO_DEBUG +/* Store the last 2 places the queue element or head was altered */ +struct qm_trace { + char * lastfile; + int lastline; + char * prevfile; + int prevline; +}; + +#define TRACEBUF struct qm_trace trace; +#define TRASHIT(x) do {(x) = (void *)-1;} while (0) + +#define QMD_TRACE_HEAD(head) do { \ + (head)->trace.prevline = (head)->trace.lastline; \ + (head)->trace.prevfile = (head)->trace.lastfile; \ + (head)->trace.lastline = __LINE__; \ + (head)->trace.lastfile = __FILE__; \ +} while (0) + +#define QMD_TRACE_ELEM(elem) do { \ + (elem)->trace.prevline = (elem)->trace.lastline; \ + (elem)->trace.prevfile = (elem)->trace.lastfile; \ + (elem)->trace.lastline = __LINE__; \ + (elem)->trace.lastfile = __FILE__; \ +} while (0) + +#else +#define QMD_TRACE_ELEM(elem) +#define QMD_TRACE_HEAD(head) +#define TRACEBUF +#define TRASHIT(x) +#endif /* QUEUE_MACRO_DEBUG */ + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST((head)); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != NULL; \ + (varp) = &SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_REMOVE_NEXT(head, curelm, field); \ + } \ + TRASHIT((elm)->field.sle_next); \ +} while (0) + +#define SLIST_REMOVE_NEXT(head, elm, field) do { \ + SLIST_NEXT(elm, field) = \ + SLIST_NEXT(SLIST_NEXT(elm, field), field); \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first;/* first element */ \ + struct type **stqh_last;/* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + + +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *)(void *) \ + ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + STAILQ_REMOVE_NEXT(head, curelm, field); \ + } \ + TRASHIT((elm)->field.stqe_next); \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_REMOVE_NEXT(head, elm, field) do { \ + if ((STAILQ_NEXT(elm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +/* + * List declarations. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ + +#if (defined(_KERNEL) && defined(INVARIANTS)) +#define QMD_LIST_CHECK_HEAD(head, field) do { \ + if (LIST_FIRST((head)) != NULL && \ + LIST_FIRST((head))->field.le_prev != \ + &LIST_FIRST((head))) \ + panic("Bad list head %p first->prev != head", (head)); \ +} while (0) + +#define QMD_LIST_CHECK_NEXT(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL && \ + LIST_NEXT((elm), field)->field.le_prev != \ + &((elm)->field.le_next)) \ + panic("Bad link elm %p next->prev != elm", (elm)); \ +} while (0) + +#define QMD_LIST_CHECK_PREV(elm, field) do { \ + if (*(elm)->field.le_prev != (elm)) \ + panic("Bad link elm %p prev->next != elm", (elm)); \ +} while (0) +#else +#define QMD_LIST_CHECK_HEAD(head, field) +#define QMD_LIST_CHECK_NEXT(elm, field) +#define QMD_LIST_CHECK_PREV(elm, field) +#endif /* (_KERNEL && INVARIANTS) */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + QMD_LIST_CHECK_NEXT(listelm, field); \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + QMD_LIST_CHECK_PREV(listelm, field); \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + QMD_LIST_CHECK_HEAD((head), field); \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_REMOVE(elm, field) do { \ + QMD_LIST_CHECK_NEXT(elm, field); \ + QMD_LIST_CHECK_PREV(elm, field); \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ + TRASHIT((elm)->field.le_next); \ + TRASHIT((elm)->field.le_prev); \ +} while (0) + +/* + * Tail queue declarations. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ + TRACEBUF \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ + TRACEBUF \ +} + +/* + * Tail queue functions. + */ +#if (defined(_KERNEL) && defined(INVARIANTS)) +#define QMD_TAILQ_CHECK_HEAD(head, field) do { \ + if (!TAILQ_EMPTY(head) && \ + TAILQ_FIRST((head))->field.tqe_prev != \ + &TAILQ_FIRST((head))) \ + panic("Bad tailq head %p first->prev != head", (head)); \ +} while (0) + +#define QMD_TAILQ_CHECK_TAIL(head, field) do { \ + if (*(head)->tqh_last != NULL) \ + panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \ +} while (0) + +#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \ + if (TAILQ_NEXT((elm), field) != NULL && \ + TAILQ_NEXT((elm), field)->field.tqe_prev != \ + &((elm)->field.tqe_next)) \ + panic("Bad link elm %p next->prev != elm", (elm)); \ +} while (0) + +#define QMD_TAILQ_CHECK_PREV(elm, field) do { \ + if (*(elm)->field.tqe_prev != (elm)) \ + panic("Bad link elm %p prev->next != elm", (elm)); \ +} while (0) +#else +#define QMD_TAILQ_CHECK_HEAD(head, field) +#define QMD_TAILQ_CHECK_TAIL(head, headname) +#define QMD_TAILQ_CHECK_NEXT(elm, field) +#define QMD_TAILQ_CHECK_PREV(elm, field) +#endif /* (_KERNEL && INVARIANTS) */ + +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + QMD_TRACE_HEAD(head1); \ + QMD_TRACE_HEAD(head2); \ + } \ +} while (0) + +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + QMD_TAILQ_CHECK_NEXT(listelm, field); \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else { \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + } \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + QMD_TAILQ_CHECK_PREV(listelm, field); \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + QMD_TAILQ_CHECK_HEAD(head, field); \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + QMD_TAILQ_CHECK_TAIL(head, field); \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + QMD_TAILQ_CHECK_NEXT(elm, field); \ + QMD_TAILQ_CHECK_PREV(elm, field); \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else { \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + QMD_TRACE_HEAD(head); \ + } \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ + TRASHIT((elm)->field.tqe_next); \ + TRASHIT((elm)->field.tqe_prev); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + + +#ifdef _KERNEL + +/* + * XXX insque() and remque() are an old way of handling certain queues. + * They bogusly assumes that all queue heads look alike. + */ + +struct quehead { + struct quehead *qh_link; + struct quehead *qh_rlink; +}; + +#ifdef __CC_SUPPORTS___INLINE + +static __inline void +insque(void *a, void *b) +{ + struct quehead *element = (struct quehead *)a, + *head = (struct quehead *)b; + + element->qh_link = head->qh_link; + element->qh_rlink = head; + head->qh_link = element; + element->qh_link->qh_rlink = element; +} + +static __inline void +remque(void *a) +{ + struct quehead *element = (struct quehead *)a; + + element->qh_link->qh_rlink = element->qh_rlink; + element->qh_rlink->qh_link = element->qh_link; + element->qh_rlink = 0; +} + +#else /* !__CC_SUPPORTS___INLINE */ + +void insque(void *a, void *b); +void remque(void *a); + +#endif /* __CC_SUPPORTS___INLINE */ + +#endif /* _KERNEL */ + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/drl/calendar.h b/drl/calendar.h new file mode 100644 index 0000000..717c8a2 --- /dev/null +++ b/drl/calendar.h @@ -0,0 +1,18 @@ +/* See the DRL-LICENSE file for this file's software license. */ + +#ifndef _CALENDAR_H_ +#define _CALENDAR_H_ + +#include "bsd_queue.h" +#include "ratetypes.h" + +#define SCHEDBITS (7) +#define SCHEDLEN (1 << SCHEDBITS) +#define SCHEDMASK (SCHEDLEN - 1) + +/** Defines a struct ident_calendar whose elements are of type struct identity + * (identity_t) */ +TAILQ_HEAD(ident_calendar, identity); + + +#endif /* _CALENDAR_H_ */ diff --git a/drl/common_accounting.h b/drl/common_accounting.h new file mode 100644 index 0000000..d656d8a --- /dev/null +++ b/drl/common_accounting.h @@ -0,0 +1,83 @@ +/* See the DRL-LICENSE file for this file's software license. */ + +/** Defines a structure that is common to all of the flow accounting + * mechanisms. This includes the aggregate rate and the time it was last + * updated. */ + +#ifndef _COMMON_ACCOUNTING_H_ +#define _COMMON_ACCOUNTING_H_ + +#include +#include +#include + +/** Representation of a flow that is to be used as a key into the table. */ +typedef struct key_flow { + + /* Identification information. Some or all of this information is used + * by the accounting table hash functions to identify flows. */ + + /** The source IP address. */ + uint32_t source_ip; + + /** The destination IP address. */ + uint32_t dest_ip; + + /** The source TCP/UDP port. */ + uint16_t source_port; + + /** The destination TCP/UDP port. */ + uint16_t dest_port; + + /** The value of the IP header protocol field. */ + uint8_t protocol; + + /* + * Packet information. This is not used by the accounting tables for + * hashing, but is useful when sampling a new packet. + */ + + /** The size of the packet (in bytes). */ + uint16_t packet_size; + + /** The time at which the packet was sent. */ + time_t packet_time; + +} key_flow; + +/** + * This structure is used to store information common to all flow accounting + * mechanisms. It includes the aggregate rate information that will be read + * by the estimation and allocation functions. + */ +typedef struct { + /** The best estimate of the rate for the current estimate interval. This + * includes EWMA smoothing. */ + uint32_t rate; + + /** The best estimate of the rate for the previous estimate inteval. This + * includes EWMA smoothing. */ + uint32_t last_rate; + + /** The instantaneous rate for the current estimate interval.*/ + uint32_t inst_rate; + + /** The instantaneous rate for the previous estimate interval.*/ + uint32_t last_inst_rate; + + /** The rate of the largest flow being tracked by the table. */ + uint32_t max_flow_rate; + + /** The time at which this structure was last updated. */ + struct timeval last_update; + + /** The number of bytes sent since the last_update time. */ + uint32_t bytes_since; + +} common_accounting_t; + +/** Determines the difference between two timeval structs (in seconds, with + * fractions). */ +#define timeval_subtract(big, small) ((double) (big.tv_sec - small.tv_sec) + (big.tv_usec - small.tv_usec) / 1000000.0) + +#endif /* _COMMON_ACCOUNTING_H_ */ diff --git a/drl/config.c b/drl/config.c new file mode 100644 index 0000000..1c56ce8 --- /dev/null +++ b/drl/config.c @@ -0,0 +1,427 @@ +/* See the DRL-LICENSE file for this file's software license. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "raterouter.h" +#include "ratetypes.h" +#include "config.h" +#include "util.h" +#include "logging.h" + +void free_ident(ident_config *ident) { + /* Free peers. */ + while (ident->peers) { + ident_peer *tofree = ident->peers; + ident->peers = ident->peers->next; + free(tofree); + } + + /* Free members. */ + while (ident->members) { + ident_member *tofree = ident->members; + ident->members = ident->members->next; + free(tofree); + } + + /* Free ident. */ + free(ident); +} + +void free_ident_list(ident_config *list) { + ident_config *tofree; + + while (list) { + tofree = list; + list = list->next; + free_ident(tofree); + } +} + +static int xid_filter(const struct dirent *d) { + if (atoi(d->d_name) > 0) + return 1; + else + return 0; +} + +int get_eligible_leaves(drl_instance_t *instance) { + struct dirent **names; + int count, i; + leaf_t *leaves = NULL; + map_handle leaf_map = allocate_map(); + + if (leaf_map == NULL) { + return ENOMEM; + } + + count = scandir("/proc/virtual", &names, xid_filter, alphasort); + + if (count < 1) { + return 1; + } + + leaves = malloc(count * sizeof(leaf_t)); + if (leaves == NULL) { + /* Couldn't allocate leaves array. Need to free names memory. */ + while (count--) { + free(names[count]); + } + free(names); + + return ENOMEM; + } + + for (i = 0; i < count; ++i) { + leaves[i].xid = atoi(names[i]->d_name); + leaves[i].parent = NULL; + + free(names[i]); + + map_insert(leaf_map, &leaves[i].xid, sizeof(leaves[i].xid), &leaves[i]); + } + + free(names); + + instance->leaf_map = leaf_map; + instance->leaves = leaves; + instance->leaf_count = count; + + return 0; +} + +static int parse_common(xmlDocPtr doc, xmlNodePtr ident, ident_config *common) { + xmlChar *id; + xmlChar *limit; + xmlChar *commfabric; + xmlChar *branch; + xmlChar *accounting; + xmlChar *ewma; + xmlChar *intervals; + xmlNodePtr fields = ident->children; + ident_peer *current = NULL; + + /* Make sure no required fields are missing. */ + id = xmlGetProp(ident, (const xmlChar *) "id"); + if (id == NULL) { + printlog(LOG_CRITICAL, "Ident missing globally unique identifier.\n"); + return EINVAL; + } else { + common->id = atoi((const char *) id); + xmlFree(id); + } + + limit = xmlGetProp(ident, (const xmlChar *) "limit"); + if (limit == NULL) { + printlog(LOG_CRITICAL, "Ident missing global rate limit.\n"); + return EINVAL; + } else { + common->limit = atoi((const char *) limit); + xmlFree(limit); + } + + commfabric = xmlGetProp(ident, (const xmlChar *) "commfabric"); + if (commfabric == NULL) { + printlog(LOG_CRITICAL, "Ident missing comm fabric specifier.\n"); + return EINVAL; + } else { + if (!xmlStrcmp(commfabric, (const xmlChar *) "MESH")) { + common->commfabric = COMM_MESH; + } else if (!xmlStrcmp(commfabric, (const xmlChar *) "GOSSIP")) { + common->commfabric = COMM_GOSSIP; + } else { + printlog(LOG_CRITICAL, "Unknown/invalid comm fabric.\n"); + xmlFree(commfabric); + return EINVAL; + } + xmlFree(commfabric); + } + + /* Only care about branching factor if we're using gossip. */ + if (common->commfabric == COMM_GOSSIP) { + branch = xmlGetProp(ident, (const xmlChar *) "branch"); + if (branch == NULL) { + printlog(LOG_CRITICAL, "Ident missing gossip branch.\n"); + return EINVAL; + } else { + common->branch = atoi((const char *) branch); + xmlFree(branch); + } + } + + accounting = xmlGetProp(ident, (const xmlChar *) "accounting"); + if (accounting == NULL) { + printlog(LOG_CRITICAL, "Ident missing accounting.\n"); + return EINVAL; + } else { + if (!xmlStrcmp(accounting, (const xmlChar *) "STANDARD")) { + common->accounting = ACT_STANDARD; + } else if (!xmlStrcmp(accounting, (const xmlChar *) "SAMPLEHOLD")) { + common->accounting = ACT_SAMPLEHOLD; + } else if (!xmlStrcmp(accounting, (const xmlChar *) "SIMPLE")) { + common->accounting = ACT_SIMPLE; + } else { + printlog(LOG_CRITICAL, "Unknown/invalid accounting table.\n"); + xmlFree(accounting); + return EINVAL; + } + xmlFree(accounting); + } + + ewma = xmlGetProp(ident, (const xmlChar *) "ewma"); + if (ewma == NULL) { + printlog(LOG_CRITICAL, "Ident missing ewma weight.\n"); + return EINVAL; + } else { + common->fixed_ewma_weight = atof((const char *) ewma); + xmlFree(ewma); + } + + intervals = xmlGetProp(ident, (const xmlChar *) "intervals"); + if (intervals == NULL) { + printlog(LOG_CRITICAL, "Ident missing interval count.\n"); + return EINVAL; + } else { + common->intervals = atoi((const char *) intervals); + xmlFree(intervals); + } + + while (fields != NULL) { + if((!xmlStrcmp(fields->name, (const xmlChar *) "peer"))) { + xmlChar *ip = xmlNodeListGetString(doc, fields->children, 1); + if (current == NULL) { + /* No peers yet. */ + common->peers = malloc(sizeof(ident_peer)); + if (common->peers == NULL) { + return ENOMEM; + } + common->peers->ip = inet_addr((const char *) ip); + common->peers->next = NULL; + common->peer_count += 1; + current = common->peers; + } else { + /* Add it to the list. */ + current->next = malloc(sizeof(ident_peer)); + if (current->next == NULL) { + return ENOMEM; + } + current = current->next; + current->ip = inet_addr((const char *) ip); + common->peer_count += 1; + current->next = NULL; + } + xmlFree(ip); + } + fields = fields->next; + } + + if (common->peers == NULL) { + printlog(LOG_CRITICAL, "Must have at least one peer.\n"); + return EINVAL; + } + + /* No errors. */ + return 0; +} + +static ident_config *parse_machine(xmlDocPtr doc, xmlNodePtr ident, parsed_configs *configs) { + ident_config *common = malloc(sizeof(ident_config)); + + if (common == NULL) { + return NULL; + } + + memset(common, 0, sizeof(ident_config)); + if (parse_common(doc, ident, common)) { + free_ident(common); + return NULL; + } + + /* No further information needed for machine-level identities. */ + common->type = IDENT_MACHINE; + common->members = NULL; + common->next = NULL; + + if (configs->last_machine == NULL) { + configs->machines = common; + configs->last_machine = common; + } else { + configs->last_machine->next = common; + configs->last_machine = common; + } + + configs->machine_count += 1; + + return common; +} + +static ident_config *parse_set(xmlDocPtr doc, xmlNodePtr ident, parsed_configs *configs) { + xmlNodePtr fields = ident->children; + ident_config *common = malloc(sizeof(ident_config)); + ident_member *current = NULL; + + if (common == NULL) { + return NULL; + } + + memset(common, 0, sizeof(ident_config)); + if (parse_common(doc, ident, common)) { + free_ident(common); + return NULL; + } + + while (fields != NULL) { + ident_member *member = NULL; + + if (!xmlStrcmp(fields->name, (const xmlChar *) "xid")) { + xmlChar *xid = xmlNodeListGetString(doc, fields->children, 1); + + if (atoi((const char *) xid) >= 0) { + member = malloc(sizeof(ident_member)); + if (member == NULL) { + free_ident(common); + xmlFree(xid); + return NULL; + } + member->type = MEMBER_XID; + sscanf((const char *) xid, "%x", &member->value); + member->next = NULL; + } else { + free_ident(common); + xmlFree(xid); + return NULL; + } + + xmlFree(xid); + } else if (!xmlStrcmp(fields->name, (const xmlChar *) "guid")) { + xmlChar *guid = xmlNodeListGetString(doc, fields->children, 1); + + if (atoi((const char *) guid) >= 0) { + member = malloc(sizeof(ident_member)); + if (member == NULL) { + free_ident(common); + xmlFree(guid); + return NULL; + } + member->type = MEMBER_GUID; + member->value = atoi((const char *) guid); + member->next = NULL; + } else { + free_ident(common); + xmlFree(guid); + return NULL; + } + + xmlFree(guid); + } + + if (member) { + if (common->members == NULL) { + common->members = member; + current = member; + } else { + current->next = member; + current = member; + } + } + + fields = fields->next; + } + + /* A sliver set must have at least one member (xid or guid) or else it is + * meaningless. */ + if (common->members == NULL) { + free_ident(common); + return NULL; + } + + common->type = IDENT_SET; + common->next = NULL; + + if (configs->last_set == NULL) { + configs->sets = common; + configs->last_set = common; + } else { + configs->last_set->next = common; + configs->last_set = common; + } + + configs->set_count += 1; + + return common; +} + +int parse_drl_config(const char *configfile, parsed_configs *configs) { + xmlDocPtr doc; + xmlNodePtr drl, ident; + + configs->machines = NULL; + configs->sets = NULL; + configs->last_machine = NULL; + configs->last_set = NULL; + configs->machine_count = 0; + configs->set_count = 0; + + if(!(doc = xmlParseFile(configfile))){ + printlog(LOG_CRITICAL, "Config file (%s) not parsed successfully.\n", configfile); + xmlFreeDoc(doc); + return EIO; + } + + if(!(drl = xmlDocGetRootElement(doc))){ + printlog(LOG_CRITICAL, "Config file (%s) has no root element.\n", configfile); + xmlFreeDoc(doc); + return EIO; + } + if(xmlStrcmp(drl->name, (const xmlChar *) "drl")){ + printlog(LOG_CRITICAL, "Config file (%s) of the wrong type, root node != drl\n", configfile); + xmlFreeDoc(doc); + return EIO; + } + + ident = drl->children; + while(ident != NULL) { + ident_config *new = NULL; + + if((!xmlStrcmp(ident->name, (const xmlChar *) "machine"))) { + new = parse_machine(doc, ident, configs); + } else if ((!xmlStrcmp(ident->name, (const xmlChar *) "set"))) { + new = parse_set(doc, ident, configs); + } else if ((!xmlStrcmp(ident->name, (const xmlChar *) "text"))) { + /* libxml seems to wrap everything inside two 'text's. */ + ident = ident->next; + continue; + } + + if (new == NULL) { + /* FIXME: Make this more descriptive. :) */ + printlog(LOG_CRITICAL, "Error occurred while parsing...\n"); + + free_ident_list(configs->machines); + free_ident_list(configs->sets); + + configs->machines = NULL; + configs->sets = NULL; + configs->last_machine = NULL; + configs->last_set = NULL; + + xmlFreeDoc(doc); + return 1; + } + + ident = ident->next; + } + + xmlFreeDoc(doc); + + /* Return the list of parsed identities. */ + return 0; +} diff --git a/drl/config.h b/drl/config.h new file mode 100644 index 0000000..e1a436f --- /dev/null +++ b/drl/config.h @@ -0,0 +1,161 @@ +/* See the DRL-LICENSE file for this file's software license. */ + +#ifndef _DRL_CONFIG_ +#define _DRL_CONFIG_ + +struct drl_instance; + +/** Enumeration of identity types. */ +enum ident_types { + + /** Type used by identities that will limit all slivers on the machine. */ + IDENT_MACHINE = 1, + + /** Type used by identities that will limit only a subset of slivers. */ + IDENT_SET = 2 +}; + +/** Enumeration of identity member types. */ +enum member_types { + + /** The member is an identifier (xid) of a single sliver. */ + MEMBER_XID = 1, + + /** The member is an identifier (guid) of another sliver-set identity. */ + MEMBER_GUID = 2 +}; + +/** + * Linked list node containing address information for one of the identity's + * peers. + */ +typedef struct ident_peer { + /** The peer's IP address. */ + in_addr_t ip; + + /** Pointer to the next peer in the list or NULL if this is the last. */ + struct ident_peer *next; +} ident_peer; + +/** + * Linked list node containing hierarchy information. For whole-machine + * identities, this is unnecessary. For sliver-set identities, this specifies + * which slivers and other sliver-sets belong in the set. + */ +typedef struct ident_member { + /** The numerical xid or guid of the member. */ + int value; + + /** Specifies whether the value is an xid or guid. */ + enum member_types type; + + /** Pointer to the next member in the list or NULL if this is the last. */ + struct ident_member *next; +} ident_member; + +/** + * Linked list node containing identity information. + */ +typedef struct ident_config { + /** The guid of this identity. */ + int id; + + /** The global DRL limit for this identity. */ + int limit; + + /** The communication fabric (COMM_MESH or COMM_GOSSIP) for this identity.*/ + enum commfabrics commfabric; + + /** The gossip branch factor (when commfabric is COMM_GOSSIP). */ + int branch; + + /** The flow accounting mechanism to be used by this identity. */ + enum accountings accounting; + + /** The fixed (1-second) ewma weight value for this identity. */ + double fixed_ewma_weight; + + /** The number of estimate intervals to wait between calls to estimate, + * allocate and enforce. */ + int intervals; + + /** The type of this identity. */ + enum ident_types type; + + /** List of the identity's peers. */ + ident_peer *peers; + + /** The number of peers. */ + int peer_count; + + /** List of the identity's members (type IDENT_SET only). */ + ident_member *members; + + /** Pointer to the next ident in the list or NULL if this is the last. */ + struct ident_config *next; +} ident_config; + +/** + * Structure used to pass two lists after parsing is complete. + */ +typedef struct parsed_configs { + /** A list of IDENT_MACHINE type identities. */ + ident_config *machines; + + /** The number of machine identities. */ + int machine_count; + + /** A list of IDENT_SET type identities. */ + ident_config *sets; + + /** The number of set identities. */ + int set_count; + + /** Pointer to the tail of the machines list. */ + ident_config *last_machine; + + /** Pointer to the tail of the sets list. */ + ident_config *last_set; +} parsed_configs; + +/** + * Frees the specified ident and all of the memory associated with it and its + * fields. + * + * @param ident The ident to free. + */ +void free_ident(ident_config *ident); + +/** + * Frees the specified list of identities and all of the memory associated + * with them. + * + * @param list The ident_config list to free. + */ +void free_ident_list(ident_config *list); + +/** + * Uses libxml2 to parse a DRL configuration XML file and converts the + * information into a linked list of identities. + * + * @param configfile The path to the XML configuration file. + * @param configs A parsed_configs structure to be filled in with linked list + * of machine and set configs. + * + * @returns zero on success, non-zero on error. + */ +int parse_drl_config(const char *configfile, parsed_configs *configs); + +/** + * Reads /proc/virtual to get a list of viable xids. It creates an array of + * leaf_t structures and a map that maps xid to the leaf_t in the array with + * the xid. + * + * @param instance The drl_instance_t to be filled in. This function sets + * the instance's leaf_map, leaves, and leaf_count fields. + * + * @returns zero on success, non-zero on error. (Possibly ENOMEM if memory + * allocation fails, or 1 if the cause of the error is unclear. */ +int get_eligible_leaves(struct drl_instance *instance); + +#endif /* _DRL_CONFIG_ */ diff --git a/drl/drl_state.c b/drl/drl_state.c new file mode 100644 index 0000000..8583d0d --- /dev/null +++ b/drl/drl_state.c @@ -0,0 +1,223 @@ +/* See the DRL-LICENSE file for this file's software license. */ + +/** Allows us to use pthread_rwlocks. */ +#define _XOPEN_SOURCE 600 + +/* malloc(), NULL */ +#include + +/* getpid() */ +#include + +/* Socket functions. */ +#include + +/* memset() */ +#include + +/* perror() */ +#include + +/* FD_ZERO() */ +#include + +#include + +#include "raterouter.h" +#include "ratetypes.h" +#include "drl_state.h" +#include "peer_comm.h" +#include "logging.h" + +extern limiter_t limiter; + +int new_comm(comm_t *comm, ident_config *config, remote_node_t *remote_nodes) { + int i; + + memset(comm, 0, sizeof(comm_t)); + + comm->comm_fabric = config->commfabric; + comm->transport_proto = UDP; + comm->remote_node_count = config->peer_count; + comm->gossip.gossip_branch = config->branch; + comm->gossip.weight = 1.0; + + pthread_mutex_init(&comm->lock, NULL); + + /* Set send function. */ + switch (config->commfabric) { + case COMM_MESH: + comm->send_function = send_udp_mesh; + break; + case COMM_GOSSIP: + comm->send_function = send_udp_gossip; + break; + } + + comm->remote_node_map = allocate_map(); + if (comm->remote_node_map == NULL) { + pthread_mutex_destroy(&comm->lock); + return ENOMEM; + } + + /* Allocate remote_limiters array and fill it in. Add remotes to map. */ + comm->remote_limiters = + malloc(config->peer_count * sizeof(remote_limiter_t)); + + if (comm->remote_limiters == NULL) { + pthread_mutex_destroy(&comm->lock); + free_map(comm->remote_node_map, 0); + return ENOMEM; + } + + memset(comm->remote_limiters, 0, config->peer_count * sizeof(remote_limiter_t)); + + for (i = 0; i < config->peer_count; ++i) { + comm->remote_limiters[i].addr = remote_nodes[i].addr; + comm->remote_limiters[i].port = remote_nodes[i].port; + comm->remote_limiters[i].outgoing.next_seqno = 1; + map_insert(comm->remote_node_map, (void *) &(remote_nodes[i]), + sizeof(remote_node_t), &comm->remote_limiters[i]); + } + + /* Allocate and initialize retrys. */ + comm->retrys = malloc(config->branch * sizeof(int)); + if (comm->retrys == NULL) { + pthread_mutex_destroy(&comm->lock); + free_map(comm->remote_node_map, 0); + free(comm->remote_limiters); + return ENOMEM; + } + + for (i = 0; i < config->branch; ++i) { + comm->retrys[i] = -1; + } + + return 0; +} + +void free_comm(comm_t *comm) { + if (comm) { + if (comm->remote_limiters) { + free(comm->remote_limiters); + } + + if (comm->remote_nodes) { + free(comm->remote_nodes); + } + + if (comm->remote_node_map) { + free_map(comm->remote_node_map, 0); + } + + pthread_mutex_destroy(&comm->lock); + + if (comm->retrys) { + free(comm->retrys); + } + } +} + +int read_comm(comm_t *comm, double *aggregate) { + remote_limiter_t *remote; + + pthread_mutex_lock(&comm->lock); + if (comm->comm_fabric == COMM_MESH) { + *aggregate = 0; + map_reset_iterate(comm->remote_node_map); + while ((remote = map_next(comm->remote_node_map))) { + /* remote->rate corresponds to the rate (GRD) or weight (FPS) + * in generated by the peer remote. */ + *aggregate += remote->rate; + + /* If we continue to read it without having heard an update, + * we start to decay its value. */ + if (remote->awol >= REMOTE_AWOL_THRESHOLD) { + remote->rate = remote->rate / 2; + } else { + remote->awol++; + } + } + *aggregate += comm->local_rate; + } else if (comm->comm_fabric == COMM_GOSSIP) { + double value = 0; + value = (comm->gossip.value / comm->gossip.weight); + value *= (comm->remote_node_count + 1); + + /* Keep around the last value so that we don't stupidly pick 0 when + * we're negative. If we pick 0, it looks to the limiter like it + * has free reign and it will take 100% of the rate allocation for + * itself. */ + if (value <= 0) { + //*aggregate = comm->gossip.last_nonzero; + *aggregate = 0; + //printf("*****Gossip value is %.3f (%u) ((%d))\n", value, *aggregate, (int) *aggregate); + } else { + *aggregate = value; + comm->gossip.last_nonzero = *aggregate; + //printf("Gossip value is %.3f (%u) ((%d))\n", value, *aggregate, (int) *aggregate); + } + } else { + printlog(LOG_CRITICAL, "read_comm: Invalid comm fabric: %d.\n", + comm->comm_fabric); + pthread_mutex_unlock(&comm->lock); + return EINVAL; + } + pthread_mutex_unlock(&comm->lock); + + //printf("read: %.3f\n", *aggregate); + + return 0; +} + +int write_local_value(comm_t *comm, const double value) { + pthread_mutex_lock(&comm->lock); + if (comm->comm_fabric == COMM_MESH) { + comm->last_local_rate = comm->local_rate; + comm->local_rate = value; + comm->rate_change = comm->local_rate - comm->last_local_rate; + } else if (comm->comm_fabric == COMM_GOSSIP) { + comm->last_local_rate = comm->local_rate; + comm->local_rate = value; + comm->rate_change = comm->local_rate - comm->last_local_rate; + /*printf("new: %f, old: %f, weight: %f, diff: %f\n", comm->gossip.value + (comm->gossip.weight * comm->rate_change), comm->gossip.value, comm->gossip.weight, comm->rate_change);*/ + /*comm->gossip.value = comm->gossip.value + (comm->gossip.weight * comm->rate_change);*/ + comm->gossip.value += comm->rate_change; + } + else { + printlog(LOG_CRITICAL, "write_local_value: Invalid comm fabric: %d.\n", + comm->comm_fabric); + pthread_mutex_unlock(&comm->lock); + return EINVAL; + } + pthread_mutex_unlock(&comm->lock); + + return 0; +} + +int send_update(comm_t *comm, uint32_t id) { + int result = 0; + + pthread_mutex_lock(&comm->lock); + + result = comm->send_function(comm, id, limiter.udp_socket); + + pthread_mutex_unlock(&comm->lock); + + return result; +} + +void *limiter_receive_thread(void *unused) { + sigset_t signal_mask; + + sigemptyset(&signal_mask); + sigaddset(&signal_mask, SIGHUP); + pthread_sigmask(SIG_BLOCK, &signal_mask, NULL); + + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + while (1) { + limiter_receive(); + } + pthread_exit(NULL); +} diff --git a/drl/drl_state.h b/drl/drl_state.h new file mode 100644 index 0000000..2b1ec5e --- /dev/null +++ b/drl/drl_state.h @@ -0,0 +1,250 @@ +/* See the DRL-LICENSE file for this file's software license. */ + +#ifndef _DRL_STATE_ +#define _DRL_STATE_ + +#define _XOPEN_SOURCE 600 + +/* FILE */ +#include + +/* uint32_t */ +#include +#include + +/* in_addr_t, in_port_t */ +#include + +/* pthread functions. */ +#include + +/* fd_set */ +#include + +/* Hash map types/functions. */ +#ifdef STANDALONE +#include "../util.h" +#else +#include "util.h" +#endif + +#define MAX_IDENTS (1024) +#define MAX_LIMITERS (128) + +#define REMOTE_AWOL_THRESHOLD (3) + +enum transports { UDP, TCP }; + +typedef struct gossipval { + int gossip_branch; + double last_nonzero; + double value; + double weight; +} gossip_t; + +typedef struct out_neighbor { + uint32_t next_seqno; + uint32_t first_seqno; + double saved_value; + double saved_weight; +} out_neighbor_t; + +typedef struct in_neighbor { + uint32_t seen_seqno; + double saved_value; + double saved_weight; +} in_neighbor_t; + +typedef struct remote_node { + in_addr_t addr; + in_port_t port; +} remote_node_t; + +typedef struct remote_limiter { + /** The last known value at the remote limiter. */ + double rate; + + in_neighbor_t incoming; + out_neighbor_t outgoing; + + /* Socket to contact this remote limiter, if using TCP. */ + int socket; + + in_addr_t addr; + in_port_t port; + + /** Flag to keep track of situations in which we read from this node's + * value more than once before receiving an update from it. We use this + * value to know when it's safe to begin decaying the remote node's value + * (because we assume that it has failed). */ + int awol; + +} remote_limiter_t; + +typedef struct comm { + /** Communication policy. (COMM_MESH, COMM_GOSSIP) */ + enum commfabrics comm_fabric; + + /** Transport protocol. */ + enum transports transport_proto; + + /** Current local value. */ + double local_rate; + + /** Previous local value. */ + double last_local_rate; + + double rate_change; + + /** The number of remote nodes in the identity */ + uint32_t remote_node_count; + + remote_node_t *remote_nodes; + + /** Array containing all known remote limiters in this identity. + * Contains the same information as the remote_node_map. */ + remote_limiter_t *remote_limiters; + + /** Hash map containing all the remote limiters in this identity. + * Indexed by the remote_node_t used to create the remote_limiter_t. + * Maps to the appropriate element of the remote_limiters array. */ + map_handle remote_node_map; + + /** A mutex to protect the comm structure. */ + pthread_mutex_t lock; + + /** Gossip values for our local identity */ + gossip_t gossip; + + /** Function pointer to send function. */ + int (*send_function)(struct comm *comm, uint32_t id, int sock); + +#if 0 + /** Thread for handling incoming TCP data. */ + pthread_t tcp_recv_thread; + + /** Descriptor set for reading TCP messages */ + fd_set fds; +#endif + + /** Array of integers specifiying which nodes, if any, have outstanding + * unacked data. When nodes fall in this category, and it's time to send, + * these nodes will be chosen first. This only affects gossip. A + * negative number means there is no retransmit necessary. Otherwise, the + * value is the index into the remote_limiters array of the necessary + * retransmit. */ + int *retrys; + +} comm_t; + +typedef struct message { + uint32_t magic; + uint32_t ident_id; + uint32_t seqno; + uint32_t min_seqno; + double value; + double weight; + uint16_t type; +} message_t; + +typedef struct hello_message { + uint32_t magic; + uint32_t ident_id; + uint16_t port; +} hello_t; + +#if 0 +struct recv_thread_args { + comm_ident_t *ident; + pthread_rwlock_t *lock; + uint16_t port; +}; +#endif + +#if 0 +/** + * Initializes the global limiter. + * + * @param ipaddr The IP address on which the limiter should listen. + * INADDR_ANY will suffice. Should be specified in network byte order. + * + * @param port The port on which the limiter should listen. Should be specified + * in network byte order. + */ +void init_limiter(const in_addr_t ipaddr, const in_port_t port); + +/** + * Deallocates the entire global limiter. + */ +void destroy_limiter(); +#endif + +/** + * Fills in the communication structure of an identity. + * + * @param comm The communication structure to be created/populated. + * + * @param config The configuration options for the identity. + * + * @param nodes An array of remote nodes belonging to this identity. + * + * @returns 0 on success, ENOMEM if memory cannot be allocated. + */ +int new_comm(comm_t *comm, ident_config *config, remote_node_t *nodes); + +/** + * Frees the memory associated with an identity's communication structure. + * + * @param comm The communication structure to free. + */ +void free_comm(comm_t *comm); + +/** + * Calculates and reads the current aggregate value for an identity. + * This value includes the locally observed value. + * + * @param comm The comm structure of the identity in question. + * + * @param aggregate The location at which the aggregate value will + * be stored. + * + * @returns 0 on success, EINVAL on error. + */ +int read_comm(comm_t *comm, double *aggregate); + +/** + * Updates the locally observed value of an identity. + * + * @param comm The comm structure of the identity to update. + * + * @param value The new locally observed value. + * + * @returns 0 on success, EINVAL on error. + */ +int write_local_value(comm_t *comm, const double value); + +/** + * Sends the local state information to one or more peer limiters in the same + * identity. If the identity is configured as a mesh, it will send to all + * peers. If the identity is configured using gossip, it will send to the + * number of peers specified by the gossip_branch field of the comm_config_t + * that was used to configure the identity. + * + * @param comm The communication structure of the identity whose value should + * be propagated. + * + * @param id The unique id of the identity that is sending. + * + * @returns 0 on success, ENOMEM if there was not enough memory, or possibly + * other E values as a result of socket-related results. + */ +int send_update(comm_t *comm, uint32_t id); + +/** + * Thread that is responsible for receiving data from other limiters. + * + * @param limiter The limiter_t that is to be doing the receiving. + */ +void *limiter_receive_thread(void *unused); + +#endif /* _DRL_STATE_ */ diff --git a/drl/estimate.c b/drl/estimate.c new file mode 100644 index 0000000..f1dd142 --- /dev/null +++ b/drl/estimate.c @@ -0,0 +1,486 @@ +/* See the DRL-LICENSE file for this file's software license. */ + +/* + * Thread to periodically calculate the estimated local limits + * Barath Raghavan 2006/2007 + * Ken Yocum 2007 + * Kevin Webb 2007/2008 + */ + +/** The size of the buffer we use to hold tc commands. */ +#define CMD_BUFFER_SIZE 200 + +/* DRL specifics */ +#include "raterouter.h" +#include "util.h" +#include "ratetypes.h" /* needs util and pthread.h */ +#include "logging.h" + +static int underlimit_flowcount_count = 0; +static int underlimit_normal_count = 0; + +/** + * Called for each identity each estimate interval. Uses flow table information + * to estimate the current aggregate rate and the rate of the individual flows + * in the table. + */ +static void estimate(identity_t *ident) { + struct timeval now; + + gettimeofday(&now, NULL); + + pthread_mutex_lock(&ident->table_mutex); /* CLUNK ! */ + + ident->table_update_function(ident->table, now, ident->ewma_weight); + + pthread_mutex_unlock(&ident->table_mutex); /* CLINK ! */ +} + +/** + * Determines the FPS weight allocation when the identity is under its current + * local rate limit. + */ +static double allocate_fps_under_limit(identity_t *ident, uint32_t local_rate, double peer_weights) { + uint32_t target = local_rate; + double ideal_weight; + double total_weight = peer_weights + ident->last_localweight; + + if (ident->flowstart) { + target = local_rate*4; + if (local_rate >= FLOW_START_THRESHOLD) { + ident->flowstart = false; + } + } + else { + /* June 16, 2008 (KCW) + * ident->flowstart gets set initially to one, but it is never set again. However, + * if a limiter gets flows and then the number of flows drops to zero, it has trouble + * increasing the limit again. */ + if (local_rate < FLOW_START_THRESHOLD) { + ident->flowstart = true; + } + } + + if (target >= ident->limit) { + ideal_weight = total_weight; + } else if (target <= 0) { + ideal_weight = 0; // no flows here + } else { + ideal_weight = ((double)target / (double)ident->limit) * total_weight; + } + +#if 0 + else if (peer_weights <= 0) { +#if 0 + // doesn't matter what we pick as our weight, so pick 1 / N. + ideal_weight = MAX_FLOW_SCALING_FACTOR / (remote_count(ident->i_handle) + 1); +#endif + ideal_weight = ((double)target / (double)ident->limit) * total_weight; + } else { +#if 0 + double divisor = (double) ident->limit - (double) target; + ideal_weight = ((double) target * peer_weights) / divisor; +#else + ideal_weight = ((double)target / (double)ident->limit) * total_weight; +#endif + } +#endif + + return ideal_weight; +} + +/** + * Determines the FPS weight allocation when the identity is over its current + * local rate limit. + */ +static double allocate_fps_over_limit(identity_t *ident) { + double ideal_weight; + + if (ident->common.max_flow_rate > 0) { + ideal_weight = (double) ident->locallimit / (double) ident->common.max_flow_rate; + + printlog(LOG_DEBUG, "%.3f %d %d FlowCount, TotalRate, MaxRate\n", + ideal_weight, ident->common.rate, ident->common.max_flow_rate); + } else { + ideal_weight = 1; + } + + return ideal_weight; +} + +/** + * Determines the amount of FPS weight to allocate to the identity during each + * estimate interval. Note that total_weight includes local weight. + */ +static uint32_t allocate_fps(identity_t *ident, double total_weight) { + common_accounting_t *ftable = &ident->common; /* Common flow table info */ + uint32_t local_rate = ftable->rate; + uint32_t ideallocal = 0; + double peer_weights; /* sum of weights of all other limiters */ + double idealweight = 0; + double last_portion = 0; + double this_portion = 0; + + static int dampen = 0; + int dampen_increase = 0; + + double ideal_under = 0; + double ideal_over = 0; + + int regime = 0; + + /* two cases: + 1. the aggregate is < limit + 2. the aggregate is >= limit + */ + peer_weights = total_weight - ident->last_localweight; + if (peer_weights < 0) { + peer_weights = 0; + } + + if (dampen == 1) { + int64_t rate_delta = + (int64_t) ftable->inst_rate - (int64_t) ftable->last_inst_rate; + double threshold = + (double) ident->limit * (double) LARGE_INCREASE_PERCENTAGE / 10; + + if (rate_delta > threshold) { + dampen_increase = 1; + printlog(LOG_DEBUG, "DAMPEN: delta(%.3f) thresh(%.3f)\n", + rate_delta, threshold); + } + } + + if (local_rate <= 0) { + idealweight = 0; + } else if (dampen_increase == 0 && (ident->locallimit <= 0 || local_rate < ident->locallimit || ident->flowstart)) { + /* We're under the limit - all flows are bottlenecked. */ + idealweight = allocate_fps_under_limit(ident, local_rate, peer_weights); + ideal_over = allocate_fps_over_limit(ident); + ideal_under = idealweight; + + if (ideal_over < idealweight) { + idealweight = ideal_over; + regime = 3; + dampen = 2; + underlimit_flowcount_count += 1; + } else { + regime = 1; + dampen = 0; + underlimit_normal_count += 1; + } + + /* Apply EWMA */ + ident->localweight = (ident->localweight * ident->ewma_weight + + idealweight * (1 - ident->ewma_weight)); + + } else { + idealweight = allocate_fps_over_limit(ident); + + /* Apply EWMA */ + ident->localweight = (ident->localweight * ident->ewma_weight + + idealweight * (1 - ident->ewma_weight)); + + /* This is the portion of the total weight in the system that was caused + * by this limiter in the last interval. */ + last_portion = ident->last_localweight / total_weight; + + /* This is the fraction of the total weight in the system that our + * proposed value for idealweight would use. */ + this_portion = ident->localweight / (peer_weights + ident->localweight); + + /* Dampen the large increase the first time... */ + if (dampen == 0 && (this_portion - last_portion > LARGE_INCREASE_PERCENTAGE)) { + ident->localweight = ident->last_localweight + (LARGE_INCREASE_PERCENTAGE * total_weight); + dampen = 1; + } else { + dampen = 2; + } + + ideal_under = allocate_fps_under_limit(ident, local_rate, peer_weights); + ideal_over = idealweight; + + regime = 2; + } + + /* Convert weight into a rate - add in our new local weight */ + total_weight = ident->localweight + peer_weights; + + /* compute local allocation: + if there is traffic elsewhere, use the weights + otherwise do a L/n allocation */ + if (total_weight > 0) { + //if (peer_weights > 0) { + ideallocal = (uint32_t) (ident->localweight * ident->limit / total_weight); + } else { + ideallocal = ident->limit / (ident->comm.remote_node_count + 1); + } + + printlog(LOG_DEBUG, "%.3f ActualWeight\n", ident->localweight); + + printlog(LOG_DEBUG, "%.3f %.3f %.3f %.3f Under / Over / Actual / Rate\n", + ideal_under / (ideal_under + peer_weights), + ideal_over / (ideal_over + peer_weights), + ident->localweight / (ident->localweight + peer_weights), + (double) local_rate / (double) ident->limit); + + printlog(LOG_DEBUG, "%.3f %.3f IdealUnd IdealOve\n",ideal_under,ideal_over); + + printf("local_rate: %d, idealweight: %.3f, localweight: %.3f, total_weight: %.3f\n", + local_rate, idealweight, ident->localweight, total_weight); + + //printf("Dampen: %d, dampen_increase: %d, peer_weights: %.3f, regime: %d\n", + // dampen, dampen_increase, peer_weights, regime); + + //printf("normal_count: %d, flowcount_count: %d\n", underlimit_normal_count, underlimit_flowcount_count); + + if (regime == 3) { + printlog(LOG_DEBUG, "MIN: min said to use flow counting, which was %.3f when other method said %.3f.\n", + ideal_over, ideal_under); + } + + printlog(LOG_DEBUG, "ideallocal is %d\n", ideallocal); + + return(ideallocal); +} + +/** + * Determines the local drop probability for a GRD identity every estimate + * interval. + */ +static double allocate_grd(identity_t *ident, double aggdemand) { + double dropprob; + double global_limit = (double) (ident->limit); + + if (aggdemand > global_limit) { + dropprob = (aggdemand-global_limit)/aggdemand; + } else { + dropprob = 0.0; + } + + //printf("local rate: %d, aggregate demand: %.3f, drop prob: %.3f\n", + // ident->common.rate, aggdemand, dropprob); + + return dropprob; +} + +/** + * Given current estimates of local rate (weight) and remote rates (weights) + * use GRD or FPS to calculate a new local limit. + */ +static void allocate(limiter_t *limiter, identity_t *ident) { + /* Represents aggregate rate for GRD and aggregate weight for FPS. */ + double comm_val = 0; + + /* Read comm_val from comm layer. */ + read_comm(&ident->comm, &comm_val); + printlog(LOG_DEBUG, "%.3f Aggregate weight/rate (FPS/GRD)\n", comm_val); + + /* Experimental printing. */ + printlog(LOG_DEBUG, "%.3f \t Kbps used rate. ID:%d\n", + (double) ident->common.rate / (double) 128, ident->id); + ident->avg_bytes += ident->common.rate; + + if (limiter->policynum == POLICY_FPS) { + ident->locallimit = allocate_fps(ident, comm_val); + ident->last_localweight = ident->localweight; + + /* Update other limiters with our weight by writing to comm layer. */ + write_local_value(&ident->comm, ident->localweight); + } else { + ident->locallimit = 0; /* Unused with GRD. */ + ident->last_localdropprob = ident->localdropprob; + ident->localdropprob = allocate_grd(ident, comm_val); + + /* Update other limiters with our rate by writing to comm layer. */ + write_local_value(&ident->comm, ident->common.rate); + } + + /* Update identity state. */ + ident->common.last_rate = ident->common.rate; +} + +/** + * This is called once per estimate interval to enforce the rate that allocate + * has decided upon. It makes calls to tc using system(). + */ +static void enforce(limiter_t *limiter, identity_t *ident) { + char cmd[CMD_BUFFER_SIZE]; + int ret = 0; + + switch (limiter->policynum) { + case POLICY_FPS: + + /* TC treats limits of 0 (8bit) as unlimited, which causes the + * entire rate limiting system to become unpredictable. In + * reality, we also don't want any limiter to be able to set its + * limit so low that it chokes all of the flows to the point that + * they can't increase. Thus, when we're setting a low limit, we + * make sure that it isn't too low by using the + * FLOW_START_THRESHOLD. */ + + if (ident->locallimit < FLOW_START_THRESHOLD) { + ident->locallimit = FLOW_START_THRESHOLD * 2; + } + + /* Do not allow the node to set a limit higher than its + * administratively assigned upper limit (bwcap). */ + if (limiter->nodelimit != 0 && ident->locallimit > limiter->nodelimit) { + ident->locallimit = limiter->nodelimit; + } + + printf("FPS: Setting local limit to %d\n", ident->locallimit); + printlog(LOG_DEBUG, "%d Limit ID:%d\n", ident->locallimit, ident->id); + + snprintf(cmd, CMD_BUFFER_SIZE, + "/sbin/tc class change dev eth0 parent 1:%x classid 1:%x htb rate 8bit ceil %dbps quantum 1600", + ident->htb_parent, ident->htb_node, ident->locallimit); + + ret = system(cmd); + + if (ret) { + /* FIXME: call failed. What to do? */ + } + break; + + case POLICY_GRD: +/* FIXME: Figure out where to enforce GRD. */ +#if 0 + for (i = 0; i < ident->num_slices; i++){ + + sprintf(cmd, "/sbin/tc qdisc change dev eth0 parent 1:1%x handle 1%x netem loss %.4f delay 40ms", + ident->xids[i],ident->xids[i], (100*ident->localdropprob)); + + ret = system(cmd); + + if (ret==-1) + print_system_error(ret); + } +#endif + break; + + default: + printlog(LOG_CRITICAL, "DRL enforce: unknown policy %d\n",limiter->policynum); + break; + } + + return; +} + +/** + * This function is periodically called to clean the stable instance's flow + * accounting tables for each identity. + */ +static void clean(drl_instance_t *instance) { + identity_t *ident = NULL; + + map_reset_iterate(instance->ident_map); + while ((ident = map_next(instance->ident_map)) != NULL) { + pthread_mutex_lock(&ident->table_mutex); + + ident->table_cleanup_function(ident->table); + + pthread_mutex_unlock(&ident->table_mutex); + } + + /* Periodically flush the log file. */ + flushlog(); +} + +static void print_averages(drl_instance_t *instance, int print_interval) { + identity_t *ident = NULL; + + map_reset_iterate(instance->ident_map); + while ((ident = map_next(instance->ident_map)) != NULL) { + ident->avg_bytes /= (double) print_interval; + //printf("avg_bytes = %f, print_interval = %d\n", ident->avg_bytes, print_interval); + printlog(LOG_DEBUG, "%.3f \t Avg rate. ID:%d\n", + ident->avg_bytes / 128, ident->id); + //printf("%.3f \t Avg rate. ID:%d\n", + // ident->avg_bytes / 128, ident->id); + ident->avg_bytes = 0; + } +} + +/** Thread function to handle local rate estimation. + * + * None of our simple hashmap functions are thread safe, so we lock the limiter + * with an rwlock to prevent another thread from attempting to modify the set + * of identities. + * + * Each identity also has a private lock for its table. This gets locked by + * table-modifying functions such as estimate and clean. + */ +void handle_estimation(void *arg) { + limiter_t *limiter = (limiter_t *) arg; + identity_t *ident = NULL; + int clean_timer, clean_wait_intervals; + useconds_t sleep_time = limiter->estintms * 1000; + uint32_t cal_slot = 0; + int print_interval = 1000 / (limiter->estintms); + + sigset_t signal_mask; + + sigemptyset(&signal_mask); + sigaddset(&signal_mask, SIGHUP); + pthread_sigmask(SIG_BLOCK, &signal_mask, NULL); + + /* Determine the number of intervals we should wait before hitting the + * specified clean interval. (Converts seconds -> intervals). */ + clean_wait_intervals = IDENT_CLEAN_INTERVAL * (1000.0 / limiter->estintms); + clean_timer = clean_wait_intervals; + + while (true) { + /* Sleep according to the delay of the estimate interval. */ + usleep(sleep_time); + + /* Grab the limiter lock for reading. This prevents identities from + * disappearing beneath our feet. */ + pthread_rwlock_rdlock(&limiter->limiter_lock); + + cal_slot = limiter->stable_instance.cal_slot & SCHEDMASK; + + /* Service all the identities that are scheduled to run during this + * tick. */ + while (!TAILQ_EMPTY(limiter->stable_instance.cal + cal_slot)) { + ident = TAILQ_FIRST(limiter->stable_instance.cal + cal_slot); + TAILQ_REMOVE(limiter->stable_instance.cal + cal_slot, ident, calendar); + + /* Update the ident's flow accouting table with the latest info. */ + estimate(ident); + + /* Determine its share of the rate allocation. */ + allocate(limiter, ident); + + /* Make tc calls to enforce the rate we decided upon. */ + enforce(limiter, ident); + + /* Tell the comm library to propagate this identity's result for + * this interval.*/ + send_update(&ident->comm, ident->id); + + /* Add ident back to the queue at a future time slot. */ + TAILQ_INSERT_TAIL(limiter->stable_instance.cal + + ((cal_slot + ident->intervals) & SCHEDMASK), + ident, calendar); + } + + print_interval--; + if (loglevel() == LOG_DEBUG && print_interval <= 0) { + print_interval = 1000 / (limiter->estintms); + print_averages(&limiter->stable_instance, print_interval); + } + + /* Check if enough intervals have passed for cleaning. */ + if (clean_timer <= 0) { + clean(&limiter->stable_instance); + clean_timer = clean_wait_intervals; + } else { + clean_timer--; + } + + limiter->stable_instance.cal_slot += 1; + + pthread_rwlock_unlock(&limiter->limiter_lock); + } +} diff --git a/drl/logging.c b/drl/logging.c new file mode 100644 index 0000000..ca3d7c1 --- /dev/null +++ b/drl/logging.c @@ -0,0 +1,25 @@ +/* See the DRL-LICENSE file for this file's software license. */ +#include + +#include "logging.h" + +FILE *logfile; +uint8_t system_loglevel; + +inline void printlog(const uint8_t level, const char *format, ...) { + va_list args; + + if (system_loglevel <= level) { + va_start(args, format); + vfprintf(logfile, format, args); + va_end(args); + } +} + +void flushlog() { + fflush(logfile); +} + +int loglevel() { + return system_loglevel; +} diff --git a/drl/logging.h b/drl/logging.h new file mode 100644 index 0000000..034614b --- /dev/null +++ b/drl/logging.h @@ -0,0 +1,29 @@ +/* See the DRL-LICENSE file for this file's software license. */ + +#ifndef _LOGGING_H_ +#define _LOGGING_H_ + +#include +#include +#include + +#define LOG_CRITICAL (3) +#define LOG_WARN (2) +#define LOG_DEBUG (1) + +/** + * Logging function. Takes format and arguments similar to printf. + */ +inline void printlog(const uint8_t level, const char *format, ...); + +/** + * Flushes the logfile to disk. + */ +void flushlog(); + +/** + * Returns the log level. + */ +int loglevel(); + +#endif /* _LOGGING_H_ */ diff --git a/drl/peer_comm.c b/drl/peer_comm.c new file mode 100644 index 0000000..cb30657 --- /dev/null +++ b/drl/peer_comm.c @@ -0,0 +1,613 @@ +/* See the DRL-LICENSE file for this file's software license. */ + +#define _XOPEN_SOURCE 600 + +/* Debug output. */ +#include +#include + +/* Socket functions. */ +#include +#include + +/* Byte ordering and address structures. */ +#include + +/* memset() */ +#include + +/* close() & usleep */ +#include + +/* Mutex lock/unlock. */ +#include + +/* perror() */ +#include + +/* select() w/ timeout */ +#include +#include + +/* assert() */ +#include + +/* sigaddset(), sigemptyset(), SIGHUP, etc. */ +#include + +/* DRL data structures. */ +#include "raterouter.h" +#include "ratetypes.h" +#include "drl_state.h" +#include "peer_comm.h" +#include "logging.h" + +extern limiter_t limiter; + +static const uint32_t MAGIC_MSG = 0x123123; +static const uint32_t MAGIC_HELLO = 0x456456; +static const uint16_t MSG = 1; +static const uint16_t ACK = 2; + +static void message_to_hbo(message_t *msg) { + msg->magic = ntohl(msg->magic); + msg->ident_id = ntohl(msg->ident_id); + msg->seqno = ntohl(msg->seqno); + msg->min_seqno = ntohl(msg->min_seqno); + msg->type = ntohs(msg->type); + /* value is a double */ + /* weight is a double */ +} + +static void message_to_nbo(message_t *msg) { + msg->magic = htonl(msg->magic); + msg->ident_id = htonl(msg->ident_id); + msg->seqno = htonl(msg->seqno); + msg->min_seqno = htonl(msg->min_seqno); + msg->type = htons(msg->type); + /* value is a double */ + /* weight is a double */ +} + +static void hello_to_hbo(hello_t *hello) { + hello->magic = ntohl(hello->magic); + hello->ident_id = ntohl(hello->ident_id); + hello->port = ntohs(hello->port); +} + +static void hello_to_nbo(hello_t *hello) { + hello->magic = htonl(hello->magic); + hello->ident_id = htonl(hello->ident_id); + hello->port = htons(hello->port); +} + +static int is_connected(remote_limiter_t *remote) { + struct sockaddr_in addr; + socklen_t addrlen = sizeof(addr); + + if (getpeername(remote->socket, (struct sockaddr *) &addr, &addrlen) == 0) + return 1; + else + return 0; +} + +static int send_ack(identity_t *ident, remote_limiter_t *remote, uint32_t seqno) { + int result = 0; + message_t msg; + struct sockaddr_in toaddr; + + memset(&toaddr, 0, sizeof(struct sockaddr_in)); + toaddr.sin_family = AF_INET; + + toaddr.sin_addr.s_addr = remote->addr; /* Already in network byte order. */ + toaddr.sin_port = remote->port; + + memset(&msg, 0, sizeof(msg)); + msg.magic = MAGIC_MSG; + msg.ident_id = ident->id; + msg.type = ACK; + msg.seqno = seqno; + + message_to_nbo(&msg); + + if (sendto(limiter.udp_socket, &msg, sizeof(msg), 0, (struct sockaddr *) &toaddr, sizeof(struct sockaddr_in)) < 0) { + printlog(LOG_WARN, "send_ack: sento failed.\n"); + result = errno; + } + + return result; +} + +void limiter_receive() { + struct sockaddr_in fromaddr; + remote_node_t sender; + socklen_t fromlen = sizeof(fromaddr); + identity_t *ident = NULL; + remote_limiter_t *remote = NULL; + message_t msg; + + if (recvfrom(limiter.udp_socket, &msg, sizeof(msg), MSG_WAITALL, (struct sockaddr *) &fromaddr, (socklen_t *) &fromlen) != sizeof(msg)) { + /* recv failed. Log and continue. */ + printlog(LOG_WARN, "recv failed to read full message.\n"); + return; + } + memset(&sender, 0, sizeof(remote_node_t)); + sender.addr = fromaddr.sin_addr.s_addr; + sender.port = fromaddr.sin_port; + + message_to_hbo(&msg); + + assert(msg.magic == MAGIC_MSG); + +#if 0 + printlog(LOG_WARN, "Rcvd (value, weight) : (%f, %f) from ident %d (net order host 0x%x port %d) key size(%d)\n", + msg.value, msg.weight, msg.ident_id, sender.addr,sender.port,sizeof(remote_node_t)); +#endif + pthread_testcancel(); + + pthread_rwlock_rdlock(&limiter.limiter_lock); + + ident = map_search(limiter.stable_instance.ident_map, &msg.ident_id, + sizeof(msg.ident_id)); + + if (ident == NULL) { + printlog(LOG_WARN, "WARN:recvd message for unknown identity.\n"); + pthread_rwlock_unlock(&limiter.limiter_lock); + return; + } + + pthread_mutex_lock(&ident->comm.lock); + + remote = map_search(ident->comm.remote_node_map, &sender, sizeof(remote_node_t)); + + if (remote == NULL) { + printlog(LOG_WARN, "WARN: recvd msg from unknown entity.\n"); + pthread_mutex_unlock(&ident->comm.lock); + pthread_rwlock_unlock(&limiter.limiter_lock); + return; + } + + switch (ident->comm.comm_fabric) { + case COMM_MESH: { + /* Use the message's value to be our new GRDrate/FPSweight for the + * message's sender. */ + remote->rate = msg.value; + + /* Reset the AWOL counter to zero since we received an update. */ + remote->awol = 0; + } + break; + + case COMM_GOSSIP: { + if (msg.type == ACK) { + if (msg.seqno == remote->outgoing.next_seqno - 1) { + int i; + + /* Ack for most recent message. Clear saved state. */ + remote->outgoing.first_seqno = remote->outgoing.next_seqno; + remote->outgoing.saved_value = 0; + remote->outgoing.saved_weight = 0; + + for (i = 0; i < ident->comm.gossip.gossip_branch; ++i) { + if (ident->comm.retrys[i] >= 0 && + remote == &ident->comm.remote_limiters[ident->comm.retrys[i]]) { + //printf("clearing spot %d, it was %d\n", i, ident->retrys[i]); + ident->comm.retrys[i] = -2; + } + } + } + /* Ignore ack if it isn't for most recent message. */ + } else { + if (msg.min_seqno > remote->incoming.seen_seqno) { + /* Entirely new information */ + remote->incoming.seen_seqno = msg.seqno; + remote->incoming.saved_value = msg.value; + remote->incoming.saved_weight = msg.weight; + ident->comm.gossip.value += msg.value; + ident->comm.gossip.weight += msg.weight; + send_ack(ident, remote, msg.seqno); + } else if (msg.seqno > remote->incoming.seen_seqno) { + /* Only some of the message is old news. */ + double diff_value = msg.value - remote->incoming.saved_value; + double diff_weight = msg.weight - remote->incoming.saved_weight; + + remote->incoming.seen_seqno = msg.seqno; + remote->incoming.saved_value = msg.value; + remote->incoming.saved_weight = msg.weight; + + ident->comm.gossip.value += diff_value; + ident->comm.gossip.weight += diff_weight; + send_ack(ident, remote, msg.seqno); + } else { + /* The entire message is old news. (Duplicate). */ + /* Do nothing. */ + } + } + } + break; + + default: { + printlog(LOG_CRITICAL, "ERR: Unknown identity comm fabric.\n"); + } + } + + pthread_mutex_unlock(&ident->comm.lock); + pthread_rwlock_unlock(&limiter.limiter_lock); +} + +#if 0 +static void limiter_accept(comm_limiter_t *limiter) { + int sock, result; + struct sockaddr_in fromaddr; + socklen_t fromlen = sizeof(fromaddr); + remote_node_t sender; + remote_limiter_t *remote; + hello_t hello; + comm_ident_t *ident; + ident_handle *handle = NULL; + + sock = accept(limiter->tcp_socket, (struct sockaddr *)&fromaddr, &fromlen); + + assert(sock > 0); + + memset(&hello, 0, sizeof(hello_t)); + result = recv(sock, &hello, sizeof(hello_t), 0); + + if (result < 0) { + close(sock); + return; /* Failure - ignore it. */ + } + + assert(result == sizeof(hello_t)); + + hello_to_hbo(&hello); + + assert(hello.magic == MAGIC_HELLO); + + memset(&sender, 0, sizeof(remote_node_t)); + sender.addr = fromaddr.sin_addr.s_addr; + sender.port = ntohs(hello.port); + + pthread_testcancel(); + + pthread_rwlock_rdlock(&limiter->rwlock); + + handle = map_search(limiter->ident_id_to_handle, (void *) &hello.ident_id, sizeof(hello.ident_id)); + + if (handle == NULL) { + printlog(LOG_WARN, "WARN:recvd hello for unknown identity.\n"); + pthread_rwlock_unlock(&limiter->rwlock); + return; + } + + ident = limiter->identities[*handle]; + assert(ident != NULL); + + pthread_mutex_lock(&ident->lock); + + remote = map_search(ident->remote_node_map, &sender, sizeof(remote_node_t)); + + if (remote == NULL) { + printlog(LOG_WARN, "WARN: Accepted connection from unknown identity.\n"); + pthread_mutex_unlock(&ident->lock); + pthread_rwlock_unlock(&limiter->rwlock); + close(sock); + return; + } + + if (is_connected(remote)) { + /* We are still connected, don't need the new socket. */ + close(sock); + pthread_mutex_unlock(&ident->lock); + pthread_rwlock_unlock(&limiter->rwlock); + return; + } + + /* We weren't connected, but we are now... */ + remote->socket = sock; + printf("Got connection on: %d\n", sock); + FD_SET(sock, &ident->fds); + + pthread_mutex_unlock(&ident->lock); + pthread_rwlock_unlock(&limiter->rwlock); +} + +static void read_tcp_message(comm_ident_t *ident, pthread_rwlock_t *limiter_rwlock, int sock) { + int result; + message_t msg; + + memset(&msg, 0, sizeof(message_t)); + + result = recv(sock, &msg, sizeof(message_t), 0); + + if (result < 0) { + pthread_rwlock_rdlock(limiter_rwlock); + pthread_mutex_lock(&ident->lock); + FD_CLR(sock, &ident->fds); + close(sock); + pthread_mutex_unlock(&ident->lock); + pthread_rwlock_unlock(limiter_rwlock); + return; + } + + assert(result == sizeof(message_t)); + + message_to_hbo(&msg); + assert(msg.magic == MAGIC_MSG); + + pthread_rwlock_rdlock(limiter_rwlock); + pthread_mutex_lock(&ident->lock); + + switch (ident->comm_fabric) { + case COMM_GOSSIP: { + ident->gossip.value += msg.value; + ident->gossip.weight += msg.weight; + } + break; + + default: { + assert(1 == 0); /* This case shouldn't happen. Punt for now... */ + } + } + pthread_mutex_unlock(&ident->lock); + pthread_rwlock_unlock(limiter_rwlock); +} + +static void ident_receive(comm_ident_t *ident, pthread_rwlock_t *limiter_rwlock) { + int select_result, i; + fd_set fds_copy; + struct timeval timeout; + + FD_ZERO(&fds_copy); + timeout.tv_sec = 15; + timeout.tv_usec = 0; + + pthread_rwlock_rdlock(limiter_rwlock); + pthread_mutex_lock(&ident->lock); + memcpy(&fds_copy, &ident->fds, sizeof(fd_set)); + pthread_mutex_unlock(&ident->lock); + pthread_rwlock_unlock(limiter_rwlock); + + /* mask interrupt signals for this thread? */ + + select_result = select(FD_SETSIZE, &fds_copy, NULL, NULL, &timeout); + + assert(select_result >= 0); + + if (select_result == 0) + return; /* Timed out */ + + for (i = 0; (i < FD_SETSIZE) && select_result; ++i) { + if (FD_ISSET(i, &fds_copy)) { + read_tcp_message(ident, limiter_rwlock, i); + select_result--; + } + } +} +#endif + +int send_udp_mesh(comm_t *comm, uint32_t id, int sock) { + int result = 0; + remote_limiter_t *remote; + message_t msg; + struct sockaddr_in toaddr; + + memset(&toaddr, 0, sizeof(struct sockaddr_in)); + toaddr.sin_family = AF_INET; + + memset(&msg, 0, sizeof(message_t)); + msg.magic = MAGIC_MSG; + msg.ident_id = id; + msg.value = comm->local_rate; + /* Do we want seqnos for mesh? We can get by without them. */ + + message_to_nbo(&msg); + + /* Iterate though and send update to all remote limiters in our identity. */ + map_reset_iterate(comm->remote_node_map); + while ((remote = map_next(comm->remote_node_map))) { + toaddr.sin_addr.s_addr = remote->addr; /* Already in network byte order. */ + toaddr.sin_port = remote->port; + if (sendto(sock, &msg, sizeof(msg), 0, (struct sockaddr *) &toaddr, sizeof(struct sockaddr_in)) < 0) { + printlog(LOG_CRITICAL, "ERR: limiter_send_mesh: sento failed.\n"); + result = errno; + printlog(LOG_CRITICAL, " - The error was |%d|\n", strerror(result)); + break; + } + } + + return result; +} + +int send_udp_gossip(comm_t *comm, uint32_t id, int sock) { + int i, j, targetid; + int result = 0; + remote_limiter_t *remote; + struct sockaddr_in toaddr; + double msg_value, msg_weight; + + memset(&toaddr, 0, sizeof(struct sockaddr_in)); + toaddr.sin_family = AF_INET; + + msg_value = comm->gossip.value / (comm->gossip.gossip_branch + 1); + msg_weight = comm->gossip.weight / (comm->gossip.gossip_branch + 1); + + for (i = 0; i < comm->gossip.gossip_branch; ++i) { + message_t msg; + + if (comm->retrys[i] >= 0) { + remote = &comm->remote_limiters[comm->retrys[i]]; + targetid = comm->retrys[i]; + //printf("%d:d:%d, ", i, comm->retrys[i]); + } else { + targetid = -2; + + while (targetid == -2) { + targetid = myrand() % comm->remote_node_count; + + for (j = 0; j < comm->gossip.gossip_branch; ++j) { + if (targetid == comm->retrys[j]) { + targetid = -2; + break; + } + } + } + + remote = &comm->remote_limiters[targetid]; + //printf("%d:r:%d, ", i, targetid); + } + + toaddr.sin_addr.s_addr = remote->addr; /* Already in network byte order. */ + toaddr.sin_port = remote->port; + + memset(&msg, 0, sizeof(message_t)); + msg.magic = MAGIC_MSG; + msg.ident_id = id; + msg.value = msg_value + remote->outgoing.saved_value; + msg.weight = msg_weight + remote->outgoing.saved_weight; + msg.seqno = remote->outgoing.next_seqno; + msg.min_seqno = remote->outgoing.first_seqno; + msg.type = MSG; + + remote->outgoing.next_seqno++; + remote->outgoing.saved_value += msg_value; + remote->outgoing.saved_weight += msg_weight; + + message_to_nbo(&msg); + + if (sendto(sock, &msg, sizeof(msg), 0, (struct sockaddr *) &toaddr, sizeof(struct sockaddr_in)) < 0) { + printlog(LOG_CRITICAL, "ERR: limiter_send_gossip: sento failed.\n"); + result = errno; + break; + } + + comm->retrys[i] = targetid; + } + //printf("\n"); + + comm->gossip.value = msg_value; + comm->gossip.weight = msg_weight; + + return result; +} + +#if 0 +int send_tcp_gossip(comm_ident_t *ident, FILE *logfile, int unused) { + int i, targetid, sock; + int result = 0; + message_t msg; + + memset(&msg, 0, sizeof(message_t)); + msg.magic = MAGIC_MSG; + msg.ident_id = ident->ident_id; + msg.value = ident->gossip.value / (ident->gossip.gossip_branch + 1); + msg.weight = ident->gossip.weight / (ident->gossip.gossip_branch + 1); + + message_to_nbo(&msg); + + for (i = 0; i < ident->gossip.gossip_branch; ++i) { + targetid = myrand() % ident->remote_node_count; + sock = ident->remote_limiters[targetid].socket; + + result = send(sock, &msg, sizeof(message_t), 0); + if (result < 0) { + result = errno; + FD_CLR(sock, &ident->fds); + close(sock); + break; + } + + assert(result == sizeof(message_t)); + } + + ident->gossip.value /= (ident->gossip.gossip_branch + 1); + ident->gossip.weight /= (ident->gossip.gossip_branch + 1); + + return result; +} +#endif + +#if 0 +void *limiter_accept_thread(void *limiter) { + sigset_t signal_mask; + + sigemptyset(&signal_mask); + sigaddset(&signal_mask, SIGHUP); + pthread_sigmask(SIG_BLOCK, &signal_mask, NULL); + + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + while (1) { + limiter_accept((comm_limiter_t *) limiter); + } + pthread_exit(NULL); +} +void *ident_receive_thread(void *recv_args) { + int i, sock, result; + struct recv_thread_args *args = (struct recv_thread_args *) recv_args; + comm_ident_t *ident = args->ident; + pthread_rwlock_t *lock = args->lock; + uint16_t port = args->port; + struct sockaddr_in addr; + socklen_t addrlen = sizeof(addr); + hello_t hello; + + free(args); + + while (1) { + memset(&hello, 0, sizeof(hello_t)); + + /*Try to connect to all remote nodes if they aren't already connected.*/ + pthread_rwlock_rdlock(lock); + pthread_mutex_lock(&ident->lock); + + hello.magic = MAGIC_HELLO; + hello.ident_id = ident->ident_id; + hello.port = ntohs(port); + + hello_to_nbo(&hello); + + for (i = 0; i < ident->remote_node_count; ++i) { + if (is_connected(&ident->remote_limiters[i])) + continue; /* Ignore if it's already connected */ + + sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock < 0) { + perror("socket"); + continue; + } + + assert(sock >= 0); + + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = ident->remote_limiters[i].port; + addr.sin_addr.s_addr = ident->remote_limiters[i].addr; + + result = connect(sock, (struct sockaddr *) &addr, addrlen); + if (result < 0) { + close(sock); + continue; + } + + result = send(sock, &hello, sizeof(hello_t), 0); + if (result < 0) { + close(sock); + continue; + } + + assert(result == sizeof(hello_t)); + + ident->remote_limiters[i].socket = sock; + printf("Connected on socket: %d\n", sock); + FD_SET(sock, &ident->fds); + } + + pthread_rwlock_unlock(lock); + pthread_mutex_unlock(&ident->lock); + + ident_receive(ident, lock); + } + pthread_exit(NULL); +} +#endif diff --git a/drl/peer_comm.h b/drl/peer_comm.h new file mode 100644 index 0000000..c8fd2e1 --- /dev/null +++ b/drl/peer_comm.h @@ -0,0 +1,21 @@ +/* See the DRL-LICENSE file for this file's software license. */ + +#ifndef _PEER_COMM_H_ +#define _PEER_COMM_H_ + +void limiter_receive(); + +#if 0 +void *limiter_accept_thread(void *limiter); + +void *ident_receive_thread(void *limiter); +#endif + +int send_udp_mesh(comm_t *comm, uint32_t id, int sock); +int send_udp_gossip(comm_t *comm, uint32_t id, int sock); + +#if 0 +int send_tcp_gossip(comm_ident_t *ident, FILE *logfile, int unused); +#endif + +#endif diff --git a/drl/raterouter.h b/drl/raterouter.h new file mode 100644 index 0000000..28c6c7f --- /dev/null +++ b/drl/raterouter.h @@ -0,0 +1,81 @@ +/* See the DRL-LICENSE file for this file's software license. */ + +#ifndef _RATEROUTER_H_ +#define _RATEROUTER_H_ + +#define _XOPEN_SOURCE 600 /* for pthread_rwlock_t */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include /* defines getifaddrs */ +#include + +enum policies { POLICY_GRD = 1, POLICY_FPS = 2 }; +enum commfabrics { COMM_MESH = 1, COMM_GOSSIP = 2 }; +enum accountings { ACT_STANDARD = 1, ACT_SAMPLEHOLD = 2, ACT_SIMPLE = 3 }; + +/* The comm library also has definitions for comfabrics. This prevents us + * from defining them twice. */ +#define COMM_DEFS + +/* global constants */ +#define IDENT_CLEAN_INTERVAL 5 /* in seconds */ +#define LIMITER_LISTEN_PORT 9001 + +/** + * The weight percentage increase that must occur before FPS does increase + * dampening. + */ +#define LARGE_INCREASE_PERCENTAGE (0.05) + +/** + * Below this rate, a limiter is basically treated as idle, and its limit is + * raised to allow for increases should the limiter suddenly become active. + * + * This is used for FPS only. See estimate.c + */ +#define FLOW_START_THRESHOLD (4096) + +/** + * All fields come from the ip protocol header. + * + * 1 byte for the protocol. + * 4 bytes for the source ip. + * 4 bytes for the destination ip. + * 2 bytes for the source port. + * 2 bytes for the destination port. + * + * 4+4+2+2+1 = 13. + */ +#define FLOWKEYSIZE (13) + +/* forward declare some structs */ +struct limiter; +struct identity; + +/* prototypes for threaded processing DRL model */ +void handle_estimation(void *arg); + +#endif diff --git a/drl/ratetypes.h b/drl/ratetypes.h new file mode 100644 index 0000000..c88c931 --- /dev/null +++ b/drl/ratetypes.h @@ -0,0 +1,245 @@ +/* See the DRL-LICENSE file for this file's software license. */ + +/* ratetypes.h + * + * Defines the main types used by DRL. + */ + +#ifndef _RATETYPES_H_ +#define _RATETYPES_H_ + +#include + +#if 0 +#include "rate_accounting/common_accounting.h" +#include "rate_accounting/standard.h" +#include "rate_accounting/samplehold.h" +#include "rate_accounting/simple.h" +#endif + +#include "calendar.h" +#include "config.h" +#include "drl_state.h" +#include "common_accounting.h" +#include "standard.h" +#include "samplehold.h" +#include "simple.h" + + +/** Represents a DRL entitiy/group. */ +typedef struct identity { + + /** A unique id for the identity. */ + uint32_t id; + + /** The global rate limit. */ + uint32_t limit; + + /** The local rate limit. */ + uint32_t locallimit; + + /** Pointer to the identity's parent in the HTB hierarchy. */ + struct identity *parent; + + /** The fixed (per second) EWMA weight. */ + double fixed_ewma_weight; + + /** The real EWMA weight, based on the fixed weight and estimate interval.*/ + double ewma_weight; + + /** Used for average rate graph generation. */ + double avg_bytes; + + /* Communication */ + + /** Communication data for this identity. */ + comm_t comm; + + /* FPS */ + + /** The node in the HTB hierarchy whose limits will be modified by this + * identity. (1:1)*/ + uint32_t htb_node; + + /** The parent of this node in the HTB hierarchy. (tc requires that the + * parent be specified in all calls the modify a node.) */ + uint32_t htb_parent; + + /** FPS current weight value. */ + double localweight; + + /** FPS previous weight value. */ + double last_localweight; + + /** A flag to indicate whether or not the identity is in the flowstart + * state. During flowstart, the identity's limit is raised to allow for + * flows to grow before incurring losses. */ + int flowstart; + + /* GRD */ + + /** GRD drop probability information. */ + double localdropprob; + + /** GRD previous drop probability information. */ + double last_localdropprob; + + /* Flow accounting machinery. */ + + /** Flow information that is common to all types of tables. + * This includes aggregate rates, update times, etc. */ + common_accounting_t common; + + /** The actual table. Uses a void pointer because it could be one + * of several different types. (standard, sample&hold, etc. ) */ + void *table; + + /** Protects the table, as it gets updated in two separate threads: + * 1) ulogd_DRL.c: the table is updated as new packet information arrives. + * 2) estimate.c: the table is used to determine rates, and it's also + * periodically cleaned. + */ + pthread_mutex_t table_mutex; + + /* Function pointers to functions to act on the table. */ + + /** Function to call for each packet. Updates the byte count for flows + * that are being tracked. */ + int (*table_sample_function)(void *, const key_flow *); + + /** Function to call on the table when it is periodically cleaned. */ + int (*table_cleanup_function)(void *); + + /** Function to call once per estimate interval to update the table's + * rate estimation. */ + void (*table_update_function)(void *, struct timeval, double); + + /** Function to call when the table should be destroyed. */ + void (*table_destroy_function)(void *); + + /* Scheduling bookkeeping. */ + + /* Pointers to other identities in the scheduling calendar. */ + TAILQ_ENTRY(identity) calendar; + + /* The number of limiter ticks at which this identity should be scheduled. + */ + uint32_t intervals; + +} identity_t; + +/** + * Represents the bottom most entity in the HTB hierarchy. For PlanetLab, + * this corresponds to sliver (identified by Vserver context id, or xid). + */ +typedef struct leaf { + /** The leaf identifier. */ + uint32_t xid; + + /** The leaf's parent in the hierarchy. This is the identity to which this + * leaf belongs. */ + identity_t *parent; +} leaf_t; + +/** + * Contains all of the identity and sliver information associated with a + * runnable instance of a local DRL node. + */ +typedef struct drl_instance { + /** An array of the node's viable leaves (slivers). */ + leaf_t *leaves; + + /** The number of items in the leaf array. */ + int leaf_count; + + /** Maps sliver xid to the leaf_t in the leaves array. */ + map_handle leaf_map; + + /** An array of the node's machine-type identities. */ + identity_t **machines; + + /** The number of items in the machines array. */ + int machine_count; + + /** An array of the node's set-type identities. */ + identity_t **sets; + + /** The number of items in the sets array. */ + int set_count; + + /** Maps identity guid to the identity_t in either the machines or sets + * arrays. */ + map_handle ident_map; + + /** The lowest machine identity in the hierarchy. This acts as the root + * for the set-identity subtree. */ + identity_t *last_machine; + + /** Acts as a circular array of lists used to schedule identities at + * some number of intervals. */ + struct ident_calendar *cal; + + /** The slot for the "current" tick in the calendar. */ + uint32_t cal_slot; + +} drl_instance_t; + +/** Represents the local node. */ +typedef struct limiter { + /** The limiter's local address in dotted quad notation. */ + char *ip; + + /** The node's individual (administrative) limit. This node should set a + * limit above this value, even when DRL says it can do so. */ + uint32_t nodelimit; + + /** The DRL policy (GRD, FPS) this node is using. */ + enum policies policynum; + + /** The estimate interval (in milliseconds). */ + int estintms; + + /** A lock to protect the state of identities so that they can be + * created/destroyed without harming any other, currently active idents. + * + * I made this an rwlock because it allows for much better parallelism. + * Creating/removing identities is uncommon, and most of the time this + * doesn't need to be held for writing. */ + pthread_rwlock_t limiter_lock; + + /** The currently running DRL instance. */ + drl_instance_t stable_instance; + + /** The next instance - if it validates. When the XML config file is + * re-read, the new structures will be incorporated into this instance. If + * everything checks out, the old (stable) instance will be freed, and this + * will be copied into stable_instance. */ + drl_instance_t new_instance; + + /* Communication fields. */ + + /** The limiter's local address as an integer (net byte order). */ + in_addr_t localaddr; + + /** The local port on which to listen (net byte order). */ + in_port_t port; + + /** Local UDP communication socket. */ + int udp_socket; + +#if 0 + /** Local TCP communication socket. */ + int tcp_socket; +#endif + + /** Limiter-wide UDP receive thread. */ + pthread_t udp_recv_thread; + +#if 0 + /** Limiter-wide TCP thread for accepting incoming connections. */ + pthread_t tcp_acpt_thread; +#endif + +} limiter_t; + +#endif diff --git a/drl/samplehold.c b/drl/samplehold.c new file mode 100644 index 0000000..4b79f3e --- /dev/null +++ b/drl/samplehold.c @@ -0,0 +1,339 @@ +/* See the DRL-LICENSE file for this file's software license. */ + +#include +#include +#include +#include +#include +#include + +#include "common_accounting.h" +#include "samplehold.h" + +static int match(const key_flow *key, const sampled_flow *flow) { + if (flow->state != FLOW_USED) + return 0; + + if (key->source_ip != flow->source_ip) + return 0; + + if (key->dest_ip != flow->dest_ip) + return 0; + + if (key->source_port != flow->source_port) + return 0; + + if (key->dest_port != flow->dest_port) + return 0; + + if (key->protocol != flow->protocol) + return 0; + + return 1; +} + +static void get_key(key_flow *key, sampled_flow *flow) { + key->source_ip = flow->source_ip; + key->dest_ip = flow->dest_ip; + key->source_port = flow->source_port; + key->dest_port = flow->dest_port; + key->protocol = flow->protocol; + + key->packet_size = 0; +} + +static void move_flow(sampled_flow *dest, sampled_flow *src) { + memmove(dest, src, sizeof(sampled_flow)); + memset(src, 0, sizeof(sampled_flow)); +} + +uint32_t sampled_table_size(const sampled_flow_table table) { + return table->size; +} + +/* + * Notes to myself... + * + * max_bytes is the maximum number of bytes that can pass though DURING THE + * MEASUREMENT INTERVAL. So, if you can have 100 Mbit/s and your measurement + * interval is 1/10 of a second, your max_bytes is 10Mbit because that's all + * you can transfer in 1/10 of a second. + * + * flow_percentage is the percentage of max_bytes that is considered an + * interesting flow. + * + * oversampling factor is a knob that tunes how accurate our results are at + * the cost of additional state/memory. + */ +sampled_flow_table sampled_table_create(uint32_t (*hash_function)(const key_flow *key), const uint32_t max_bytes, const uint32_t flow_percentage, const uint32_t oversampling_factor, common_accounting_t *common) { + sampled_flow_table table = malloc(sizeof(struct sampled_flow_table)); + double base_size = (double) 100 / (double) flow_percentage; + + if (table == NULL) { + return NULL; + } + + table->capacity = (uint32_t) ((base_size * oversampling_factor) * 1.03); + table->size = 0; + table->hash_function = hash_function; + table->sample_prob = (double) (((double) table->capacity / (double) max_bytes) * (double) RANDOM_GRANULARITY); + table->threshold = (double) ((double) flow_percentage / 100) * max_bytes; + + table->largest = NULL; + table->backing = malloc(sizeof(sampled_flow) * table->capacity); + + if (table->backing == NULL) { + free(table); + return NULL; + } + + memset(table->backing, 0, sizeof(sampled_flow) * table->capacity); + + srand(time(NULL)); + + table->common = common; + gettimeofday(&table->common->last_update, NULL); + + return table; +} + +void sampled_table_destroy(sampled_flow_table table) { + free(table->backing); + free(table); +} + +sampled_flow *sampled_table_lookup(sampled_flow_table table, const key_flow *key) { + uint32_t hash = table->hash_function(key) % table->capacity; + uint32_t location = hash; + + do { + if (table->backing[location].state == FLOW_FREE) { + /* It ain't here... */ + return NULL; + } + + if (match(key, &table->backing[location])) { + /* Got it! */ + return &table->backing[location]; + } + + location++; + if (location == table->capacity) { + location = 0; + } + } while (location != hash); + + return NULL; +} + +int sampled_table_sample(sampled_flow_table table, const key_flow *key) { + sampled_flow *lookup = sampled_table_lookup(table, key); + int random_number; + double packet_prob; + + /* First we update the common accouting information so that we have accurate + * aggregate information. */ + table->common->bytes_since += key->packet_size; + + /* Below here we're dealing with individual flows. */ + + /* It's already in the table, update it. */ + if (lookup != NULL) { + lookup->bytes += key->packet_size; + return 1; + } + + /* It's not in the table, probabilistically sample it. */ + packet_prob = table->sample_prob * (double) key->packet_size; + random_number = rand() % RANDOM_GRANULARITY; + + if (random_number < packet_prob) { + /* It's being sampled - add it to the table. */ + uint32_t hash = table->hash_function(key) % table->capacity; + uint32_t location = hash; + + do { + if (table->backing[location].state == FLOW_FREE || + table->backing[location].state == FLOW_DELETED) { + lookup = &table->backing[location]; + break; + } + + location++; + if (location == table->capacity) { + location = 0; + } + } while (location != hash); + + if (lookup == NULL) { + /* Table is full!?! */ + printf("Full table!\n"); + return 0; + } + + table->size += 1; + + lookup->bytes = key->packet_size; + lookup->source_ip = key->source_ip; + lookup->dest_ip = key->dest_ip; + lookup->source_port = key->source_port; + lookup->dest_port = key->dest_port; + lookup->protocol = key->protocol; + lookup->state = FLOW_USED; + lookup->last_bytes = 0; + lookup->rate = 0; + + gettimeofday(&lookup->last_update, NULL); + + return 1; + } + + /* Not sampled. */ + return 0; +} + +int sampled_table_cleanup(sampled_flow_table table) { + /* This should... + * 1) Remove "small" flows from the table. + * 2) Compact the table so that the remaining flows are closer to their + * hash locations. + * 3) Reset the state of deleted flows to free. + */ + + /* How it might work... + * 1) Scan through the backing array. + * 2) If the flow is small, memset it to 0. + * It it's large, add it to a linked list. + * 3) For all items in the linked list, hash them and put them in the + * correct location. + */ + + /* For now though, we're going to do it the inefficient way and loop + * through the backing twice. + */ + + int i; + + /* Clear small items. */ + for (i = 0; i < table->capacity; ++i) { + if (table->backing[i].state == FLOW_USED && table->backing[i].bytes > table->threshold) { + /* It gets to stick around. */ + } else { + /* It dies... */ + memset(&table->backing[i], 0, sizeof(sampled_flow)); + } + } + + /* Compact the table and put things closer to their hash locations. */ + for (i = 0; i < table->capacity; ++i) { + if (table->backing[i].state == FLOW_USED) { + uint32_t hash; + key_flow key; + + get_key(&key, &table->backing[i]); + hash = table->hash_function(&key) % table->capacity; + + if (i == hash) { + /* Already in the best place */ + table->backing[i].bytes = 0; + table->backing[i].last_bytes = 0; + table->backing[i].rate = 0; + } else { + uint32_t location = hash; + + do { + if (table->backing[location].state == FLOW_FREE) { + move_flow(&table->backing[location], &table->backing[i]); + table->backing[location].bytes = 0; + table->backing[location].last_bytes = 0; + table->backing[location].rate = 0; + break; + } + + location++; + if (location == table->capacity) { + location = 0; + } + } while (location != hash); + } + } + } + + table->largest = NULL; + + return 0; +} + +void sampled_table_update_flows(sampled_flow_table table, struct timeval now, double ewma_weight) { + int i = 0; + uint32_t largest_rate = 0; + uint32_t rate_delta = 0; + double time_delta = 0; + double unweighted_rate = 0; + + /* Update common aggregate information. */ + time_delta = timeval_subtract(now, table->common->last_update); + + if (time_delta <= 0) { + unweighted_rate = 0; + } else { + unweighted_rate = table->common->bytes_since / time_delta; + } + + table->common->last_inst_rate = table->common->inst_rate; + table->common->inst_rate = unweighted_rate; + + table->common->last_rate = table->common->rate; + + /* If the rate is zero, then we don't know anything yet. Don't apply EWMA + * in that case. */ + if (table->common->rate == 0) { + table->common->rate = unweighted_rate; + } else { + table->common->rate = table->common->rate * ewma_weight + + unweighted_rate * (1 - ewma_weight); + } + + table->common->bytes_since = 0; + table->common->last_update = now; + + /* Update per-flow information. */ + table->largest = &table->backing[i]; + largest_rate = table->backing[i].rate; + + for (i = 0; i < table->capacity; ++i) { + if (table->backing[i].state == FLOW_USED) { + rate_delta = table->backing[i].bytes - table->backing[i].last_bytes; + time_delta = timeval_subtract(now, table->backing[i].last_update); + + /* Calculate the unweighted rate. Be careful not to divide by + * something silly. */ + if (time_delta <= 0) { + unweighted_rate = 0; + } else { + unweighted_rate = rate_delta / time_delta; + } + + if (table->backing[i].rate == 0) { + table->backing[i].rate = unweighted_rate; + } else { + table->backing[i].rate = (table->backing[i].rate * ewma_weight + + unweighted_rate * (1 - ewma_weight)); + } + + table->backing[i].last_bytes = table->backing[i].bytes; + table->backing[i].last_update = now; + + if (table->backing[i].rate > largest_rate) { + largest_rate = table->backing[i].rate; + table->largest = &table->backing[i]; + } + } + } + + table->common->max_flow_rate = largest_rate; +} + +sampled_flow *sampled_table_largest(sampled_flow_table table) { + return table->largest; +} diff --git a/drl/samplehold.h b/drl/samplehold.h new file mode 100644 index 0000000..5a554ef --- /dev/null +++ b/drl/samplehold.h @@ -0,0 +1,165 @@ +/* See the DRL-LICENSE file for this file's software license. */ + +/** + * Implements the Sample and hold accounting mechanism as described in "New + * Directions in Traffic Measurement and Accounting" by Cristian Estan and + * George Varghese (SIGCOMM 2002). + * + * Basic idea: + * Randomly sample packets with some probability. For every sampled packet, + * if it isn't already in our flow table, add it. Once a flow is in the table, + * EVERY packet belonging to the flow subsequently updates the table + * information. + * + */ + +/* My notes: + * Let p be the probability of samping a BYTE. + * Let s be the size of a packet. + * Then we approximate the probability of samping the entire packet as p * s. + */ + +#ifndef __SAMPLEHOLD__ +#define __SAMPLEHOLD__ + +#include + +#define FLOW_FREE 0 +#define FLOW_DELETED 1 +#define FLOW_USED 2 + +#define RANDOM_GRANULARITY 1000 + +/** In-table representation of a flow that has been sampled. */ +typedef struct sampled_flow { + + /* Flow-specific values. */ + + /** The rate of the flow in the current estimate interval. */ + uint32_t rate; + + /** The total number of bytes this flow has sent during this cleaning + * interval. + */ + uint32_t bytes; + + /** The total number of bytes this flow had sent during this cleaning interval + * as of the last rate estimate update. */ + uint32_t last_bytes; + + /** The time at which this flow was last updated. */ + struct timeval last_update; + + /* Identification information. */ + + /** The flow's source IP address. */ + uint32_t source_ip; + + /** The flow's destination IP address. */ + uint32_t dest_ip; + + /** The flow's source port. */ + uint16_t source_port; + + /** The flow's destination port. */ + uint16_t dest_port; + + /** The flow's protocol. This corresponds to the protocol field of the IP + * header. */ + uint8_t protocol; + + /** Bookkeeping to keep track of the state of the flow in the table. */ + uint8_t state; + +} sampled_flow; + +/** + * The structure in which flows are stored. + */ +struct sampled_flow_table { + + /** Pointer to the common flow information for the identity that owns this + * sampled flow table. This is updated with aggregate information. */ + common_accounting_t *common; + + /* Table properties. */ + + /** The maximum capacity of the table. */ + uint32_t capacity; + + /** The current size of the table. */ + uint32_t size; + + /** Hash function pointer. */ + uint32_t (*hash_function)(const key_flow *key); + + /** Pointer to the array that backs the flow table. */ + sampled_flow *backing; + + /** Pointer to the flow in backing with the largest rate. */ + sampled_flow *largest; + + /** The probability of sampling a byte. */ + double sample_prob; + + /** Threshold for keeping things around during clean (bytes). */ + uint32_t threshold; + +}; + +/** The type sampled_flow_table is really a pointer to a struct + * sampled_flow_table. */ +typedef struct sampled_flow_table *sampled_flow_table; + +/**** Table API ****/ + +/** + * Creates a new table with the specified maximum byte count, percentage + * of byte count to classify as an interesting flow, and an oversampling factor. + * + * Returns the new table or NULL on failure. + */ +sampled_flow_table sampled_table_create(uint32_t (*hash_function)(const key_flow *key), uint32_t max_bytes, uint32_t flow_percentage, uint32_t oversampling_factor, common_accounting_t *common); + +/** + * Destroys the specified table. + */ +void sampled_table_destroy(sampled_flow_table table); + +/** + * Finds the data associated with the specified key. + * + * Returns a pointer to the sampled_flow or NULL if the key is not in the table. + */ +sampled_flow *sampled_table_lookup(sampled_flow_table table, const key_flow *key); + +/** + * This is the function that should be called on every packet. It will first + * check to see if the flow is in the table. If so, it updates the flow's + * table information. If not, it will probabilistically sample and add the + * flow to the table. + * + * Returns 1 if, after the call, the flow is in the table. 0 If it is not + * in the table. + */ +int sampled_table_sample(sampled_flow_table table, const key_flow *key); + +/** + * Returns the number of elements in the table. + */ +uint32_t sampled_table_size(const sampled_flow_table table); + +/** Cleans the table by removing "small" flows and relocating the "big" ones + * to their best hash locations. */ +int sampled_table_cleanup(sampled_flow_table table); + +/** + * Updates the rate information for all flows in the table according to the + * specified current time and EWMA weight. + */ +void sampled_table_update_flows(sampled_flow_table table, struct timeval now, double ewma_weight); + +/** Returns the largest flow in the table or NULL if there isn't one. */ +sampled_flow *sampled_table_largest(sampled_flow_table table); + +#endif /* __SAMPLEHOLD__ */ diff --git a/drl/simple.c b/drl/simple.c new file mode 100644 index 0000000..fe54abe --- /dev/null +++ b/drl/simple.c @@ -0,0 +1,81 @@ +/* See the DRL-LICENSE file for this file's software license. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common_accounting.h" +#include "simple.h" +#include "logging.h" + +simple_flow_table simple_table_create(common_accounting_t *common) { + simple_flow_table table = malloc(sizeof(struct sim_flow_table)); + + if (table == NULL) { + return NULL; + } + + memset(table, 0, sizeof(struct sim_flow_table)); + table->common = common; + table->hash_function = NULL; + + gettimeofday(&table->common->last_update, NULL); + + return table; +} + +void simple_table_destroy(simple_flow_table table) { + free(table); +} + +int simple_table_sample(simple_flow_table table, const key_flow *key) { + /* Update aggregate. */ + table->common->bytes_since += key->packet_size; + + return 0; +} + +int simple_table_cleanup(simple_flow_table table) { + return 0; +} + +void simple_table_update_flows(simple_flow_table table, struct timeval now, double ewma_weight) { + double time_delta; + double unweighted_rate; + + time_delta = timeval_subtract(now, table->common->last_update); + + if (time_delta <= 0) { + unweighted_rate = 0; + } else { + unweighted_rate = table->common->bytes_since / time_delta; + } + + table->common->last_inst_rate = table->common->inst_rate; + table->common->inst_rate = unweighted_rate; + + table->common->last_rate = table->common->rate; + + /* If the rate is zero, then we don't know anything yet. Don't apply EWMA + * in that case. */ + if (table->common->rate == 0) { + table->common->rate = unweighted_rate; + } else { + table->common->rate = table->common->rate * ewma_weight + + unweighted_rate * (1 - ewma_weight); + } + + table->common->bytes_since = 0; + table->common->last_update = now; + + /* We don't track flow rates in this table. (Not suitable for FPS) */ + table->common->max_flow_rate = 0; +} diff --git a/drl/simple.h b/drl/simple.h new file mode 100644 index 0000000..1afb016 --- /dev/null +++ b/drl/simple.h @@ -0,0 +1,58 @@ +/* See the DRL-LICENSE file for this file's software license. */ + +/** + * Defines the simplest flow accouting table. It only keeps track of + * aggregate rate information in the common table. It does no + * individual flow accounting. + * + */ + +#ifndef _SIMPLE_ACCOUNTING_H_ +#define _SIMPLE_ACCOUNTING_H_ + +#include + +/** The "table" that stores the aggregate information. It's constructed of two + * main pieces. + */ +struct sim_flow_table { + + /* Pointer to the common flow information for the identity that owns this + * sampled flow table. This is updated with aggregate information. */ + common_accounting_t *common; + + uint32_t (*hash_function)(const key_flow *key); + +}; + +typedef struct sim_flow_table *simple_flow_table; + +/** + * Creates a new table. Note that the hash function is never used by this type + * of table. + * + * Returns the new table or NULL on failure. + */ +simple_flow_table simple_table_create(common_accounting_t *common); + +/** + * Destroys the specified table. + */ +void simple_table_destroy(simple_flow_table table); + +/** + * Updates the state of the table given a newly acquired packet. + * + * This function will always return zero because this type of table stores no + * flow information. + */ +int simple_table_sample(simple_flow_table table, const key_flow *key); + +/** Cleans the table. This is a no-op for this type of table. */ +int simple_table_cleanup(simple_flow_table table); + +/** Updates the aggregate rate information. */ +void simple_table_update_flows(simple_flow_table table, struct timeval now, +double ewma_weight); + +#endif /* _SIMPLE_ACCOUNTING_H_ */ diff --git a/drl/standard.c b/drl/standard.c new file mode 100644 index 0000000..cadafee --- /dev/null +++ b/drl/standard.c @@ -0,0 +1,314 @@ +/* See the DRL-LICENSE file for this file's software license. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common_accounting.h" +#include "standard.h" +#include "logging.h" + +standard_flow_table standard_table_create(uint32_t (*hash_function)(const key_flow *key), common_accounting_t *common) { + standard_flow_table table = malloc(sizeof(struct std_flow_table)); + + if (table == NULL) { + return NULL; + } + + memset(table, 0, sizeof(struct std_flow_table)); + table->common = common; + table->hash_function = hash_function; + + gettimeofday(&table->common->last_update, NULL); + + return table; +} + +void standard_table_destroy(standard_flow_table table) { + standard_flow *current, *next; + + if ((current = table->flows_head)) { + while (current->next) { + next = current->next; + free(current); + current = next; + } + free(current); + } + + free(table); +} + +/* Looks for the flow in the table. If the flow isn't there, it allocates a + * place for it. */ +standard_flow *standard_table_lookup(standard_flow_table table, const key_flow *key) { + uint32_t hash; + standard_flow *flow; + struct in_addr src, dst; + char sip[22], dip[22]; + + if (table == NULL) { + return NULL; + } + + hash = table->hash_function(key); + + /* Find the flow, if it's there. */ + for (flow = table->flows[hash]; flow; flow = flow->nexth) { + if (flow->source_ip == key->source_ip && + flow->dest_ip == key->dest_ip && + flow->source_port == key->source_port && + flow->dest_port == key->dest_port && + flow->protocol == key->protocol) { + break; + } + } + + if (flow == NULL) { + flow = malloc(sizeof(standard_flow)); + if (flow == NULL) { + printf("Malloc returned null.\n"); + printlog(LOG_CRITICAL, "ALLOC: Malloc returned NULL.\n"); + return NULL; + } + + memset(flow, 0, sizeof(standard_flow)); + flow->protocol = key->protocol; + flow->source_ip = key->source_ip; + flow->dest_ip = key->dest_ip; + flow->source_port = key->source_port; + flow->dest_port = key->dest_port; + flow->last_packet = key->packet_time; + gettimeofday(&flow->last_update, NULL); + + /* Add the flow to the hash list. */ + flow->nexth = table->flows[hash]; + table->flows[hash] = flow; + + /* Add the flow to the linked list. */ + if (table->flows_tail) { + flow->prev = table->flows_tail; + table->flows_tail->next = flow; + table->flows_tail = flow; + } else { + table->flows_head = table->flows_tail = flow; + /* next and prev are already null due to memset above. */ + } + + src.s_addr = ntohl(flow->source_ip); + dst.s_addr = ntohl(flow->dest_ip); + strcpy(sip, inet_ntoa(src)); + strcpy(dip, inet_ntoa(dst)); + printlog(LOG_DEBUG, "ALLOC:%s:%hd -> %s:%hd\n", sip, + flow->source_port, dip, flow->dest_port); + } + + return flow; +} + +int standard_table_sample(standard_flow_table table, const key_flow *key) { + standard_flow *flow; + + assert(table != NULL); + assert(table->common != NULL); + + /* Update aggregate. */ + table->common->bytes_since += key->packet_size; + + /* Update flow. */ + flow = standard_table_lookup(table, key); + if (flow == NULL) { + return 0; + } + + flow->bytes_since += key->packet_size; + flow->last_packet = key->packet_time; + + return 1; +} + +void standard_table_remove(standard_flow_table table, standard_flow *flow) { + key_flow key; + uint32_t hash; + standard_flow *current, *prev; + + assert(flow); + + /* Remove the flow from the hash list. */ + key.source_ip = flow->source_ip; + key.dest_ip = flow->dest_ip; + key.source_port = flow->source_port; + key.dest_port = flow->dest_port; + key.protocol = flow->protocol; + + hash = table->hash_function(&key); + + assert(table->flows[hash]); + + if (table->flows[hash] == flow) { + /* It's the head of the hash list. */ + table->flows[hash] = flow->nexth; + } else { + prev = table->flows[hash]; + current = table->flows[hash]->nexth; + + while (current != NULL) { + if (current == flow) { + prev->nexth = flow->nexth; + break; + } else { + prev = current; + current = current->next; + } + } + + assert(current != NULL); + } + + /* Remove the flow from the linked list. */ + if (flow->prev == NULL && flow->next == NULL) { + /* It's the head, tail, and only element of the list. */ + assert(table->flows_head == flow); + assert(table->flows_tail == flow); + + table->flows_head = NULL; + table->flows_tail = NULL; + } else if (flow->prev == NULL) { + /* It's the head of the list. */ + assert(table->flows_head == flow); + + table->flows_head = flow->next; + + if (table->flows_head != NULL) { + table->flows_head->prev = NULL; + } + } else if (flow->next == NULL) { + /* It's the tail of the list. */ + assert(table->flows_tail == flow); + + table->flows_tail = flow->prev; + + table->flows_tail->next = NULL; + } else { + /* Not the head or tail of the list. */ + assert(table->flows_head != flow); + + flow->prev->next = flow->next; + + if (flow->next != NULL) { + flow->next->prev = flow->prev; + } + } + + memset(flow, 0, sizeof(standard_flow)); + + /* Free the flow. */ + free(flow); +} + +int standard_table_cleanup(standard_flow_table table) { + standard_flow *current = table->flows_head; + standard_flow *remove; + time_t now = time(NULL); + + while (current != NULL) { + if (current->last_packet + FLOW_IDLE_TIME <= now) { + /* Flow hasn't received a packet in the time limit - kill it. */ + remove = current; + current = current->next; + + standard_table_remove(table, remove); + } else { + current = current->next; + } + } + + return 0; +} + +void standard_table_update_flows(standard_flow_table table, struct timeval now, double ewma_weight) { + uint32_t maxflowrate = 0; + double time_delta; + double unweighted_rate; + standard_flow *current; + struct in_addr src, dst; + char sip[22], dip[22]; + + time_delta = timeval_subtract(now, table->common->last_update); + + if (time_delta <= 0) { + unweighted_rate = 0; + } else { + unweighted_rate = table->common->bytes_since / time_delta; + } + + table->common->last_inst_rate = table->common->inst_rate; + table->common->inst_rate = unweighted_rate; + + table->common->last_rate = table->common->rate; + + /* If the rate is zero, then we don't know anything yet. Don't apply EWMA + * in that case. */ + if (table->common->rate == 0) { + table->common->rate = unweighted_rate; + } else { + table->common->rate = table->common->rate * ewma_weight + + unweighted_rate * (1 - ewma_weight); + } + + table->common->bytes_since = 0; + table->common->last_update = now; + + //printf("Flows: "); + + /* Update per-flow information. */ + for (current = table->flows_head; current; current = current->next) { + time_delta = timeval_subtract(now, current->last_update); + + if (time_delta <= 0) { + unweighted_rate = 0; + } else { + unweighted_rate = current->bytes_since / time_delta; + } + + current->last_rate = current->rate; + + if (current->rate == 0) { + current->rate = unweighted_rate; + } else { + current->rate = current->rate * ewma_weight + + unweighted_rate * (1 - ewma_weight); + } + + current->bytes_since = 0; + current->last_update = now; + + if (current->rate > maxflowrate) { + maxflowrate = current->rate; + } + + //printf("%d, ", current->rate); + + src.s_addr = ntohl(current->source_ip); + dst.s_addr = ntohl(current->dest_ip); + strcpy(sip, inet_ntoa(src)); + strcpy(dip, inet_ntoa(dst)); + printlog(LOG_DEBUG, "FLOW: (%p) %s:%d -> %s:%d at %d\n", current, + sip, current->source_port, + dip, current->dest_port, + current->rate); + } + + //printf("\n"); + printlog(LOG_DEBUG, "FLOW:--\n--\n"); + + table->common->max_flow_rate = maxflowrate; +} diff --git a/drl/standard.h b/drl/standard.h new file mode 100644 index 0000000..59c45f7 --- /dev/null +++ b/drl/standard.h @@ -0,0 +1,150 @@ +/* See the DRL-LICENSE file for this file's software license. */ + +/* + * Defines the standard "perfect" flow accounting table. + * + */ + +#ifndef _STANDARD_ACCOUNTING_H_ +#define _STANDARD_ACCOUNTING_H_ + +#include + +/** The number of hash buckets in the table. */ +#define FLOW_HASH_SIZE 1024 + +/** The number of seconds after which a flow is considered to be inactive. + * Inactive flows will be removed from the table during the next call to the + * cleanup function. */ +#define FLOW_IDLE_TIME 10 + +/** Representation of a flow in a standard table. */ +typedef struct std_flow { + /* Flow information. */ + + /** The rate of the flow in the current estimate interval. */ + uint32_t rate; + + /** The rate of the flow in the previous estimate interval. */ + uint32_t last_rate; + + /** The number of bytes this flow has sent since the last update. */ + uint32_t bytes_since; + + /** The time at which this flow was last updated. */ + struct timeval last_update; + + /** The time at which the most recent packet in this flow was received. */ + time_t last_packet; + + /* Identification information. */ + + /** The flow's source IP address. */ + uint32_t source_ip; + + /** The flow's destination IP address. */ + uint32_t dest_ip; + + /** The flow's source port. */ + uint16_t source_port; + + /** The flow's destination port. */ + uint16_t dest_port; + + /** The flow's protocol. This corresponds to the protocol field of the IP + * header. */ + uint8_t protocol; + + /* Table state. */ + + /** Pointer to the next flow in the hash list. */ + struct std_flow *nexth; + + /** Pointers to the next flow in the linked list. */ + struct std_flow *next; + + /** Pointers to the previous flow in the linked list. */ + struct std_flow *prev; + +} standard_flow; + +/** + * The "table" that stores the flows. It's constructed of two main pieces. + * + * The first is an array of hash buckets. Flows are classified into buckets + * by hashing the flow's values (key flow) using the table's hash function. + * Flows are chained together as a list in each bucket to deal with collisions. + * + * The second is a simple doubly linked list containing every flow in the table. + */ +struct std_flow_table { + + /** Pointer to the common flow information for the identity that owns this + * sampled flow table. This is updated with aggregate information. */ + common_accounting_t *common; + + /* Table structures. */ + + /** Hash buckets - each is a list of flows. */ + struct std_flow *flows[FLOW_HASH_SIZE]; + + /** The head of the linked list of flows. */ + struct std_flow *flows_head; + + /** The tail of the linked list of flows. */ + struct std_flow *flows_tail; + + /** Function pointer to the function that will yield the hash of a + * key_flow. + */ + uint32_t (*hash_function)(const key_flow *key); + +}; + +/** The type standard_flow_table is really a pointer to a struct + * std_flow_table. */ +typedef struct std_flow_table *standard_flow_table; + +/** + * Creates a new table that will use the specified hash function. + * + * Returns the new table or NULL on failure. + */ +standard_flow_table standard_table_create(uint32_t (*hash_function)(const key_flow *key), common_accounting_t *common); + +/** + * Destroys the specified table. + */ +void standard_table_destroy(standard_flow_table table); + +/** + * Looks for a flow that matches the given key in the specified table. If a + * matching flow is not found, this function will allocate a new flow for the + * key. + * + * Returns a pointer to the flow that matches the key or NULL if there is no + * matching flow and a new flow couldn't be allocated. + */ +standard_flow *standard_table_lookup(standard_flow_table table, const key_flow *key); + +/** + * Updates the state of the table given a newly acquired packet. + * + * Returns 1 if the flow is in the table. 0 otherwise (indicating that memory + * could not be allocated to add a new flow to the table for the given key. + */ +int standard_table_sample(standard_flow_table table, const key_flow *key); + +/** + * Cleans the table by removing flow entires for any flow that hasn't seen a + * new packet in the interval specified by FLOW_IDLE_TIME seconds. + */ +int standard_table_cleanup(standard_flow_table table); + +/** + * Updates the rate information for all flows in the table according to the + * specified current time and EWMA weight. + */ +void standard_table_update_flows(standard_flow_table table, struct timeval now, double ewma_weight); + +#endif /* _STANDARD_ACCOUNTING_H_ */ diff --git a/drl/ulogd_DRL.c b/drl/ulogd_DRL.c new file mode 100644 index 0000000..5d7ca7e --- /dev/null +++ b/drl/ulogd_DRL.c @@ -0,0 +1,1374 @@ +/* See the DRL-LICENSE file for this file's software license. */ + +/* + * ulogd output target for DRL: GRD and FPS + * + * Ken Yocum + * + * Original shell of this code from ulogd_NETFLOW + * Like that code, we keep track of per-slice data rates + * out of this slice. Thus we are rate limiting particular slices + * across multiple boxes, ensuring that their outbound rate does not + * exceed some fixed limit. + * + * Fabric: static mesh + * + * Enforcer: linux drop percentage. + * + * This file reads packets from the netlink socket. It updates all + * the hashmaps which track how much data has arrived per flow. + * It starts two threads for this limiter. + * One thread handles periodic estimation. + * The other thread handles communication with other limiters. + * + * + * Code map + * + * ulogd_DRL: attach to netlink socket, accept packets. replaces ratelimit.cc + * util.c: generic hashing functions, flow comparisons, sundry items. + * gossip.c: Recv gossip, send gossip. + * peer_comm.c: Thread to listen for updates from other limiters. + * estimate.c: Thread to calculate the local limits. + * + * + * Ken Yocum + * 2007 + * + * Some code appropriated from ulogd_NETFLOW: + * + * Mark Huang + * Copyright (C) 2004-2005 The Trustees of Princeton University + * + * Based on admindump.pl by Mic Bowman and Paul Brett + * Copyright (c) 2002 Intel Corporation + * + */ + +/* Enable GNU glibc extensions */ +#define _GNU_SOURCE + +#include +#include + +/* va_start() and friends */ +#include + +/* ispunct() */ +#include + +/* strstr() and friends */ +#include + +/* dirname() and basename() */ +#include + +/* fork() and wait() */ +#include +#include +#include + +/* errno and assert() */ +#include +#include + +/* getopt_long() */ +#include + +/* time() and friends */ +#include +#include + +/* inet_aton() */ +#include +#include +#include + +/* ICMP definitions */ +#include +#include + +/* stat() */ +#include + +/* pthread_create() */ +#include + +/* flock() */ +#include + +/* Signal definitions - so that we can catch SIGHUP and update config. */ +#include + +#include +#include + +/* Perhaps useful for files within vservers? */ +#if !defined(STANDALONE) && HAVE_LIBPROPER +#include +#endif + +/* + * Jenkins hash support + * lives in raterouter.h + */ + +/* DRL specifics */ +#include "raterouter.h" +#include "util.h" +#include "calendar.h" +#include "ratetypes.h" /* needs util and pthread.h */ +#include "logging.h" + +/* + * /etc/ulogd.conf configuration options + * Add the config options for DRL. + */ + +static config_entry_t drl_configfile = { + .next = NULL, + .key = "drl_configfile", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_MANDATORY, + .u = { .string = "drl.xml" }, +}; + +/** The administrative bandwidth limit (mbps) for the local node. The node + * will not set a limit higher than this, even when distributed capacity is + * available. Set to 0 for no limit. */ +static config_entry_t nodelimit = { + .next = &drl_configfile, + .key = "nodelimit", + .type = CONFIG_TYPE_INT, + .options = CONFIG_OPT_MANDATORY, + .u = { .value = 0 }, +}; + +/** Determines the verbosity of logging. */ +static config_entry_t drl_loglevel = { + .next = &nodelimit, + .key = "drl_loglevel", + .type = CONFIG_TYPE_INT, + .options = CONFIG_OPT_MANDATORY, + .u = { .value = LOG_WARN }, +}; + +/** The path of the logfile. */ +static config_entry_t drl_logfile = { + .next = &drl_loglevel, + .key = "drl_logfile", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_MANDATORY, + .u = { .string = "drl_logfile.log" }, +}; + +/** The choice of DRL protocol. */ +static config_entry_t policy = { + .next = &drl_logfile, + .key = "policy", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_MANDATORY, + .u = { .string = "GRD" }, +}; + +/** The estimate interval, in milliseconds. */ +static config_entry_t estintms = { + .next = &policy, + .key = "estintms", + .type = CONFIG_TYPE_INT, + .options = CONFIG_OPT_MANDATORY, + .u = { .value = 100 }, +}; + +#define config_entries (&estintms) + +/* + * Debug functionality + */ + +#ifdef DMALLOC +#include +#endif + +#define NIPQUAD(addr) \ + ((unsigned char *)&addr)[0], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[3] + +#define IPQUAD(addr) \ + ((unsigned char *)&addr)[3], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[0] + + + +/* Salt for the hash functions */ +static int salt; + +/* + * Hash slice name lookups on context ID. + */ + +/* Special context IDs */ +#define UNKNOWN_XID -1 +#define ROOT_XID 0 + +enum { + CONNECTION_REFUSED_XID = 65536, /* MAX_S_CONTEXT + 1 */ + ICMP_ECHOREPLY_XID, + ICMP_UNREACH_XID, +}; + + +/* globals */ +pthread_t estimate_thread; +pthread_t signal_thread; +pthread_t comm_thread; +uint32_t local_ip = 0; +limiter_t limiter; +extern FILE *logfile; +extern uint8_t system_loglevel; + +/* functions */ + +static inline uint32_t +hash_flow(uint8_t protocol, uint32_t src_ip, uint16_t src_port, uint32_t dst_ip, uint16_t dst_port) +{ + unsigned char mybytes[FLOWKEYSIZE]; + mybytes[0] = protocol; + *(uint32_t*)(&(mybytes[1])) = src_ip; + *(uint32_t*)(&(mybytes[5])) = dst_ip; + *(uint32_t*)(&(mybytes[9])) = (src_port << 16) | dst_port; + return jhash(mybytes,FLOWKEYSIZE,salt) & (FLOW_HASH_SIZE - 1); +} + +uint32_t sampled_hasher(const key_flow *key) { + return hash_flow(key->protocol, key->source_ip, key->source_port, key->dest_ip, key->dest_port); +} + +uint32_t standard_hasher(const key_flow *key) { + return hash_flow(key->protocol, key->source_ip, key->source_port, key->dest_ip, key->dest_port); +} + +struct intr_id { + char* name; + ulog_iret_t *res; +}; + +/* Interesting keys */ +enum { + OOB_TIME_SEC = 0, + OOB_MARK, + IP_SADDR, + IP_DADDR, + IP_TOTLEN, + IP_PROTOCOL, + TCP_SPORT, + TCP_DPORT, + TCP_ACK, + TCP_FIN, + TCP_SYN, + TCP_RST, + UDP_SPORT, + UDP_DPORT, + ICMP_TYPE, + ICMP_CODE, + GRE_FLAG_KEY, + GRE_VERSION, + GRE_KEY, + PPTP_CALLID, +}; + +#define INTR_IDS (sizeof(intr_ids)/sizeof(intr_ids[0])) +static struct intr_id intr_ids[] = { + [OOB_TIME_SEC] = { "oob.time.sec", 0 }, + [OOB_MARK] = { "oob.mark", 0 }, + [IP_SADDR] = { "ip.saddr", 0 }, + [IP_DADDR] = { "ip.daddr", 0 }, + [IP_TOTLEN] = { "ip.totlen", 0 }, + [IP_PROTOCOL] = { "ip.protocol", 0 }, + [TCP_SPORT] = { "tcp.sport", 0 }, + [TCP_DPORT] { "tcp.dport", 0 }, + [TCP_ACK] = { "tcp.ack", 0 }, + [TCP_FIN] = { "tcp.fin", 0 }, + [TCP_SYN] = { "tcp.syn", 0 }, + [TCP_RST] = { "tcp.rst", 0 }, + [UDP_SPORT] = { "udp.sport", 0 }, + [UDP_DPORT] = { "udp.dport", 0 }, + [ICMP_TYPE] = { "icmp.type", 0 }, + [ICMP_CODE] = { "icmp.code", 0 }, + [GRE_FLAG_KEY] = { "gre.flag.key", 0 }, + [GRE_VERSION] = { "gre.version", 0 }, + [GRE_KEY] = { "gre.key", 0 }, + [PPTP_CALLID] = { "pptp.callid", 0 }, +}; + +#define GET_VALUE(x) intr_ids[x].res->value + +#define DATE(t) ((t) / (24*60*60) * (24*60*60)) + +static int _output_drl(ulog_iret_t *res) +{ + int xid; + uint32_t src_ip, dst_ip; + uint16_t src_port, dst_port; + uint8_t protocol; + + key_flow key; + identity_t *ident; + leaf_t *leaf; + + protocol = GET_VALUE(IP_PROTOCOL).ui8; + src_ip = GET_VALUE(IP_SADDR).ui32; + dst_ip = GET_VALUE(IP_DADDR).ui32; + xid = GET_VALUE(OOB_MARK).ui32; + + switch (protocol) { + + case IPPROTO_TCP: + src_port = GET_VALUE(TCP_SPORT).ui16; + dst_port = GET_VALUE(TCP_DPORT).ui16; + break; + + case IPPROTO_UDP: + /* netflow had an issue with many udp flows and set + * src_port=0 to handle it. We don't. + */ + src_port = GET_VALUE(UDP_SPORT).ui16; + + /* + * traceroutes create a large number of flows in the db + * this is a quick hack to catch the most common form + * of traceroute (basically we're mapping any UDP packet + * in the 33435-33524 range to the "trace" port, 33524 is + * 3 packets * nhops (30). + */ + dst_port = GET_VALUE(UDP_DPORT).ui16; + if (dst_port >= 33435 && dst_port <= 33524) + dst_port = 33435; + break; + + case IPPROTO_ICMP: + src_port = GET_VALUE(ICMP_TYPE).ui8; + dst_port = GET_VALUE(ICMP_CODE).ui8; + + /* + * We special case some of the ICMP traffic that the kernel + * always generates. Since this is attributed to root, it + * creates significant "noise" in the output. We want to be + * able to quickly see that root is generating traffic. + */ + if (xid == ROOT_XID) { + if (src_port == ICMP_ECHOREPLY) + xid = ICMP_ECHOREPLY_XID; + else if (src_port == ICMP_UNREACH) + xid = ICMP_UNREACH_XID; + } + break; + + case IPPROTO_GRE: + if (GET_VALUE(GRE_FLAG_KEY).b) { + if (GET_VALUE(GRE_VERSION).ui8 == 1) { + /* Get PPTP call ID */ + src_port = GET_VALUE(PPTP_CALLID).ui16; + } else { + /* XXX Truncate GRE keys to 16 bits */ + src_port = (uint16_t) GET_VALUE(GRE_KEY).ui32; + } + } else { + /* No key available */ + src_port = 0; + } + dst_port = 0; + break; + + default: + /* This is the default key for packets from unsupported protocols */ + src_port = 0; + dst_port = 0; + break; + } + + key.protocol = protocol; + key.source_ip = src_ip; + key.dest_ip = dst_ip; + key.source_port = src_port; + key.dest_port = dst_port; + key.packet_size = GET_VALUE(IP_TOTLEN).ui16; + key.packet_time = (time_t) GET_VALUE(OOB_TIME_SEC).ui32; + + pthread_rwlock_rdlock(&limiter.limiter_lock); /* CLUNK! */ + + leaf = (leaf_t *) map_search(limiter.stable_instance.leaf_map, &xid, sizeof(xid)); + + /* Even if the packet doesn't match any specific xid, it should still + * count in the machine-type tables. This catches root (xid == 0) and + * unclassified (xid = fff) packets, which don't have map entries. */ + if (leaf == NULL) { + ident = limiter.stable_instance.last_machine; + } else { + ident = leaf->parent; + } + + while (ident) { + pthread_mutex_lock(&ident->table_mutex); + + /* Update the identity's table. */ + ident->table_sample_function(ident->table, &key); + + pthread_mutex_unlock(&ident->table_mutex); + + ident = ident->parent; + } + + pthread_rwlock_unlock(&limiter.limiter_lock); /* CLINK! */ + + return 0; +} + +/* get all key id's for the keys we are intrested in */ +static int get_ids(void) +{ + int i; + struct intr_id *cur_id; + + for (i = 0; i < INTR_IDS; i++) { + cur_id = &intr_ids[i]; + cur_id->res = keyh_getres(keyh_getid(cur_id->name)); + if (!cur_id->res) { + ulogd_log(ULOGD_ERROR, + "Cannot resolve keyhash id for %s\n", + cur_id->name); + return 1; + } + } + return 0; +} + +static void free_identity(identity_t *ident) { + if (ident) { + free_comm(&ident->comm); + + if (ident->table) { + ident->table_destroy_function(ident->table); + } + + pthread_mutex_destroy(&ident->table_mutex); + + free(ident); + } +} + +static void free_identity_map(map_handle map) { + identity_t *tofree = NULL; + + map_reset_iterate(map); + while ((tofree = (identity_t *) map_next(map))) { + free_identity(tofree); + } + + free_map(map, 0); +} + +static void free_instance(drl_instance_t *instance) { + if (instance->leaves) + free(instance->leaves); + if (instance->leaf_map) + free_map(instance->leaf_map, 0); + if (instance->ident_map) + free_identity_map(instance->ident_map); + if (instance->machines) + free(instance->machines); + if (instance->sets) + free(instance->sets); + if (instance->cal) { + free(instance->cal); + } + + memset(instance, 0, sizeof(drl_instance_t)); +} + +static void free_failed_config(parsed_configs configs, drl_instance_t *instance) { + /* Free configs. */ + if (configs.machines) + free_ident_list(configs.machines); + if (configs.sets) + free_ident_list(configs.sets); + + /* Free instance. */ + if (instance) + free_instance(instance); +} + +static identity_t *new_identity(ident_config *config) { + identity_t *ident = malloc(sizeof(identity_t)); + remote_node_t *comm_nodes = malloc(sizeof(remote_node_t)*config->peer_count); + ident_peer *peer = config->peers; + int peer_slot = 0; + + if (ident == NULL) { + return NULL; + } + + if (comm_nodes == NULL) { + free(ident); + return NULL; + } + + memset(ident, 0, sizeof(identity_t)); + memset(comm_nodes, 0, config->peer_count * sizeof(remote_node_t)); + + ident->id = config->id; + ident->limit = (uint32_t) (((double) config->limit * 1000000.0) / 8.0); + ident->fixed_ewma_weight = config->fixed_ewma_weight; + ident->intervals = config->intervals; + ident->ewma_weight = pow(ident->fixed_ewma_weight, + (limiter.estintms/1000.0) * config->intervals); + ident->parent = NULL; + + pthread_mutex_init(&ident->table_mutex, NULL); + switch (config->accounting) { + case ACT_STANDARD: + ident->table = + standard_table_create(standard_hasher, &ident->common); + + /* Ugly function pointer casting. Makes things sufficiently + * generic, though. */ + ident->table_sample_function = + (int (*)(void *, const key_flow *)) standard_table_sample; + ident->table_cleanup_function = + (int (*)(void *)) standard_table_cleanup; + ident->table_update_function = + (void (*)(void *, struct timeval, double)) standard_table_update_flows; + ident->table_destroy_function = + (void (*)(void *)) standard_table_destroy; + break; + + case ACT_SAMPLEHOLD: + ident->table = sampled_table_create(sampled_hasher, + ident->limit * IDENT_CLEAN_INTERVAL, + 1, 20, &ident->common); + + ident->table_sample_function = + (int (*)(void *, const key_flow *)) sampled_table_sample; + ident->table_cleanup_function = + (int (*)(void *)) sampled_table_cleanup; + ident->table_update_function = + (void (*)(void *, struct timeval, double)) sampled_table_update_flows; + ident->table_destroy_function = + (void (*)(void *)) sampled_table_destroy; + break; + + case ACT_SIMPLE: + ident->table = simple_table_create(&ident->common); + + ident->table_sample_function = + (int (*)(void *, const key_flow *)) simple_table_sample; + ident->table_cleanup_function = + (int (*)(void *)) simple_table_cleanup; + ident->table_update_function = + (void (*)(void *, struct timeval, double)) simple_table_update_flows; + ident->table_destroy_function = + (void (*)(void *)) simple_table_destroy; + break; + } + + /* Make sure the table was allocated. */ + if (ident->table == NULL) { + free(ident); + return NULL; + } + + while (peer) { + comm_nodes[peer_slot].addr = peer->ip; + comm_nodes[peer_slot].port = htons(LIMITER_LISTEN_PORT); + peer = peer->next; + peer_slot += 1; + } + + if (new_comm(&ident->comm, config, comm_nodes)) { + printlog(LOG_CRITICAL, "Failed to create communication structure.\n"); + return NULL; + } + + ident->comm.remote_nodes = comm_nodes; + + return ident; +} + +/* Determines the validity of the parameters of one ident_config. + * + * 0 valid + * 1 invalid + */ +static int validate_config(ident_config *config) { + /* Limit must be a positive integer. */ + if (config->limit < 1) { + return 1; + } + + /* Commfabric must be a valid choice (COMM_MESH or COMM_GOSSIP). */ + if (config->commfabric != COMM_MESH && + config->commfabric != COMM_GOSSIP) { + return 1; + } + + /* If commfabric is COMM_GOSSIP, this must be a positive integer. */ + if (config->commfabric == COMM_GOSSIP && config->branch < 1) { + return 1; + } + + /* Accounting must be a valid choice (ACT_STANDARD, ACT_SAMPLEHOLD, + * ACT_SIMPLE). */ + if (config->accounting != ACT_STANDARD && + config->accounting != ACT_SAMPLEHOLD && + config->accounting != ACT_SIMPLE) { + return 1; + } + + /* Ewma weight must be greater than or equal to zero. */ + if (config->fixed_ewma_weight < 0) { + return 1; + } + + /* Note: Parsing stage requires that each ident has at least one peer. */ + return 0; +} + +/* 0 success + * non-zero failure + */ +static int validate_configs(parsed_configs configs, drl_instance_t *instance) { + + ident_config *mlist = configs.machines; + ident_config *slist = configs.sets; + ident_config *tmp = NULL; + int i = 0; + + while (mlist) { + /* ID must be non-zero and unique. */ + /* This is ugly and hackish, but this function will be called rarely. + * I'm tired of trying to be clever. */ + if (mlist->id < 0) { + printlog(LOG_CRITICAL, "Negative ident id: %d (%x) ?\n", mlist->id, mlist->id); + return EINVAL; + } + tmp = mlist->next; + while (tmp) { + if (mlist->id == tmp->id) { + printlog(LOG_CRITICAL, "Duplicate ident id: %d (%x)\n", mlist->id, mlist->id); + return EINVAL; + } + tmp = tmp->next; + } + tmp = configs.sets; + while (tmp) { + if (mlist->id == tmp->id) { + printlog(LOG_CRITICAL, "Duplicate ident id: %d (%x)\n", mlist->id, mlist->id); + return EINVAL; + } + tmp = tmp->next; + } + + if (validate_config(mlist)) { + printlog(LOG_CRITICAL, "Invalid ident parameters for id: %d (%x)\n", mlist->id, mlist->id); + return EINVAL; + } + + mlist = mlist->next; + } + + instance->sets = malloc(configs.set_count * sizeof(identity_t *)); + if (instance->sets == NULL) { + return ENOMEM; + } + + memset(instance->sets, 0, configs.set_count * sizeof(identity_t *)); + instance->set_count = configs.set_count; + + /* For sets, make sure that the hierarchy is valid. */ + while (slist) { + ident_member *members = slist->members; + + /* ID must be non-zero and unique. */ + if (slist->id < 0) { + printlog(LOG_CRITICAL, "Negative ident id: %d (%x) ?\n", slist->id, slist->id); + return EINVAL; + } + tmp = slist->next; + while (tmp) { + if (slist->id == tmp->id) { + printlog(LOG_CRITICAL, "Duplicate ident id: %d (%x)\n", slist->id, slist->id); + return EINVAL; + } + tmp = tmp->next; + } + + if (validate_config(slist)) { + printlog(LOG_CRITICAL, "Invalid ident parameters for id: %d (%x)\n", slist->id, slist->id); + return EINVAL; + } + + /* Allocate an identity_t for this set-type identity. */ + instance->sets[i] = new_identity(slist); + + if (instance->sets[i] == NULL) { + return ENOMEM; + } + + /* Loop through children and look up each in leaf or ident map + * depending on the type of child. Set the child's parent pointer + * to the identity we just created above, unless it is already set, + * in which case we have an error. */ + while (members) { + identity_t *child_ident = NULL; + leaf_t *child_leaf = NULL; + + switch (members->type) { + case MEMBER_XID: + child_leaf = map_search(instance->leaf_map, &members->value, + sizeof(members->value)); + if (child_leaf == NULL) { + return EINVAL; + } + if (child_leaf->parent != NULL) { + /* Error - This leaf already has a parent. */ + return EINVAL; + } + child_leaf->parent = instance->sets[i]; + break; + case MEMBER_GUID: + child_ident = map_search(instance->ident_map, &members->value, + sizeof(members->value)); + if (child_ident == NULL) { + return EINVAL; + } + if (child_ident->parent != NULL) { + /* Error - This identity already has a parent. */ + return EINVAL; + } + child_ident->parent = instance->sets[i]; + break; + default: + /* Error - shouldn't be possible. */ + break; + } + members = members->next; + } + + map_insert(instance->ident_map, &instance->sets[i]->id, + sizeof(instance->sets[i]->id), instance->sets[i]); + + slist = slist->next; + i++; + } + return 0; +} + +static int init_identities(parsed_configs configs, drl_instance_t *instance) { + int i; + ident_config *config = configs.machines; + leaf_t *leaf = NULL; + + instance->cal = malloc(sizeof(struct ident_calendar) * SCHEDLEN); + + if (instance->cal == NULL) { + return ENOMEM; + } + + for (i = 0; i < SCHEDLEN; ++i) { + TAILQ_INIT(instance->cal + i); + } + instance->cal_slot = 0; + + instance->machines = malloc(configs.machine_count * sizeof(drl_instance_t *)); + + if (instance->machines == NULL) { + return ENOMEM; + } + + memset(instance->machines, 0, configs.machine_count * sizeof(drl_instance_t *)); + instance->machine_count = configs.machine_count; + + /* Allocate and add the machine identities. */ + for (i = 0; i < configs.machine_count; ++i) { + instance->machines[i] = new_identity(config); + + if (instance->machines[i] == NULL) { + return ENOMEM; + } + + /* The first has no parent - it is the root. All others have the + * previous ident as their parent. */ + if (i == 0) { + instance->machines[i]->parent = NULL; + } else { + instance->machines[i]->parent = instance->machines[i - 1]; + } + + instance->last_machine = instance->machines[i]; + + /* Add the ident to the guid->ident map. */ + map_insert(instance->ident_map, &instance->machines[i]->id, + sizeof(instance->machines[i]->id), instance->machines[i]); + + config = config->next; + + TAILQ_INSERT_TAIL(instance->cal + (instance->cal_slot & SCHEDMASK), + instance->machines[i], calendar); + } + + /* Connect the set subtree to the machines. Any set or leaf without a + * parent will take the last machine as its parent. */ + + /* Leaves... */ + map_reset_iterate(instance->leaf_map); + while ((leaf = (leaf_t *) map_next(instance->leaf_map))) { + if (leaf->parent == NULL) { + leaf->parent = instance->last_machine; + } + } + + /* Sets... */ + for (i = 0; i < instance->set_count; ++i) { + if (instance->sets[i]->parent == NULL) { + instance->sets[i]->parent = instance->last_machine; + } + + TAILQ_INSERT_TAIL(instance->cal + (instance->cal_slot & SCHEDMASK), + instance->sets[i], calendar); + } + + /* Success. */ + return 0; +} + +static void print_instance(drl_instance_t *instance) { + leaf_t *leaf = NULL; + identity_t *ident = NULL; + + map_reset_iterate(instance->leaf_map); + while ((leaf = (leaf_t *) map_next(instance->leaf_map))) { + printf("%x:", leaf->xid); + ident = leaf->parent; + while (ident) { + printf("%d:",ident->id); + ident = ident->parent; + } + printf("Leaf's parent pointer is %p\n", leaf->parent); + } + + printf("instance->last_machine is %p\n", instance->last_machine); +} + +static int assign_htb_hierarchy(drl_instance_t *instance) { + int i, j; + int next_node = 0x11; + + /* Chain machine nodes under 1:10. */ + for (i = 0; i < instance->machine_count; ++i) { + if (instance->machines[i]->parent == NULL) { + /* Top node. */ + instance->machines[i]->htb_parent = 0x10; + } else { + /* Pointerific! */ + instance->machines[i]->htb_parent = + instance->machines[i]->parent->htb_node; + } + + instance->machines[i]->htb_node = next_node; + next_node += 1; + } + + next_node += 0x10; + + /* Add set nodes under machine nodes. Iterate backwards to ensure parent is + * already there. */ + for (j = (instance->set_count - 1); j >= 0; --j) { + if (instance->sets[j]->parent == NULL) { + instance->sets[j]->htb_parent = 0x10; + } else { + instance->sets[j]->htb_parent = instance->sets[j]->parent->htb_node; + } + instance->sets[j]->htb_node = next_node; + + next_node += 1; + } + + return 0; +} + +/* Added this so that I could comment one line and kill off all of the + * command execution. */ +static int execute_cmd(const char *cmd) { + return system(cmd); +} + +static int create_htb_hierarchy(drl_instance_t *instance) { + char cmd[300]; + int i, j, k; + + /* Nuke the hierarchy. */ + sprintf(cmd, "tc qdisc del dev eth0 root handle 1: htb"); + execute_cmd(cmd); + printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd); + + /* Re-initialize the basics. */ + sprintf(cmd, "tc qdisc add dev eth0 root handle 1: htb default 1fff"); + if (execute_cmd(cmd)) { + return 1; + } + printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd); + sprintf(cmd, "tc class add dev eth0 parent 1: classid 1:1 htb rate 1000mbit ceil 1000mbit"); + if (execute_cmd(cmd)) { + return 1; + } + printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd); + + /* Add back 1:10. (Nodelimit : Megabits/sec -> bits/second)*/ + if (limiter.nodelimit) { + sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:1 classid 1:10 htb rate 8bit ceil %lubit", + (unsigned long) limiter.nodelimit * 1024 * 1024); + } else { + sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:1 classid 1:10 htb rate 8bit ceil 1000mbit"); + } + + if (execute_cmd(cmd)) { + return 1; + } + printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd); + + /* Add back 1:20. */ + sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:1 classid 1:20 htb rate 8bit ceil 1000mbit"); + + if (execute_cmd(cmd)) { + return 1; + } + printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd); + + + /* Add machines. */ + for (i = 0; i < instance->machine_count; ++i) { + sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:%x classid 1:%x htb rate 8bit ceil %lubit", + instance->machines[i]->htb_parent, + instance->machines[i]->htb_node, + (unsigned long) instance->machines[i]->limit * 1024 * 1024); + + if (execute_cmd(cmd)) { + return 1; + } + printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd); + } + + /* Add sets. */ + for (j = (instance->set_count - 1); j >= 0; --j) { + sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:%x classid 1:%x htb rate 8bit ceil %lubit", + instance->sets[j]->htb_parent, + instance->sets[j]->htb_node, + (unsigned long) instance->sets[j]->limit * 1024 * 1024); + + if (execute_cmd(cmd)) { + return 1; + } + printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd); + } + + /* Add leaves. FIXME: Set static sliver limit as ceil here! */ + for (k = 0; k < instance->leaf_count; ++k) { + if (instance->leaves[k].parent == NULL) { + sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:10 classid 1:1%x htb rate 8bit ceil %lubit", + instance->leaves[k].xid, + (unsigned long) 100 * 1024 * 1024); + } else { + sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:%x classid 1:1%x htb rate 8bit ceil %lubit", + instance->leaves[k].parent->htb_node, + instance->leaves[k].xid, + (unsigned long) 100 * 1024 * 1024); + } + + if (execute_cmd(cmd)) { + return 1; + } + printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd); + + sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:20 classid 1:2%x htb rate 8bit ceil 1000mbit", + instance->leaves[k].xid); + + if (execute_cmd(cmd)) { + return 1; + } + printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd); + } + + /* Add 1:1000 and 1:2000 */ + if (instance->last_machine == NULL) { + sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:10 classid 1:1000 htb rate 8bit ceil 1000mbit"); + } else { + sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:%x classid 1:1000 htb rate 8bit ceil 1000mbit", + instance->last_machine->htb_node); + } + + if (execute_cmd(cmd)) { + return 1; + } + printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd); + sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:20 classid 1:2000 htb rate 8bit ceil 1000mbit"); + + if (execute_cmd(cmd)) { + return 1; + } + printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd); + + /* Add 1:1fff and 1:2fff */ + if (instance->last_machine == NULL) { + sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:10 classid 1:1fff htb rate 8bit ceil 1000mbit"); + } else { + sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:%x classid 1:1fff htb rate 8bit ceil 1000mbit", + instance->last_machine->htb_node); + } + + if (execute_cmd(cmd)) { + return 1; + } + printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd); + sprintf(cmd, "/sbin/tc class add dev eth0 parent 1:20 classid 1:2fff htb rate 8bit ceil 1000mbit"); + + if (execute_cmd(cmd)) { + return 1; + } + printlog(LOG_DEBUG, "HTB_cmd: %s\n", cmd); + + return 0; +} + +/* init_drl + * + * Initialize this limiter with options + * Open UDP socket for peer communication + */ +static int init_drl(void) { + parsed_configs configs; + struct sockaddr_in server_address; + + memset(&limiter, 0, sizeof(limiter_t)); + + /* Setup logging. */ + system_loglevel = (uint8_t) drl_loglevel.u.value; + logfile = fopen(drl_logfile.u.string, "w"); + + if (logfile == NULL) { + printf("Couldn't open logfile - "); + perror("fopen()"); + exit(EXIT_FAILURE); + } + + printlog(LOG_CRITICAL, "ulogd_DRL initializing . . .\n"); + + limiter.nodelimit = (uint32_t) (((double) nodelimit.u.value * 1000000.0) / 8.0); + + init_hashing(); /* for all hash maps */ + + pthread_rwlock_init(&limiter.limiter_lock,NULL); + + /* determine our local IP by iterating through interfaces */ + if ((limiter.ip = get_local_ip())==0) { + printlog(LOG_CRITICAL, + "ulogd_DRL unable to aquire local IP address, not registering.\n"); + return (false); + } + limiter.localaddr = inet_addr(limiter.ip); + limiter.port = htons(LIMITER_LISTEN_PORT); + limiter.udp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (limiter.udp_socket < 0) { + printlog(LOG_CRITICAL, "Failed to create UDP socket().\n"); + return false; + } + + memset(&server_address, 0, sizeof(server_address)); + server_address.sin_family = AF_INET; + server_address.sin_addr.s_addr = limiter.localaddr; + server_address.sin_port = limiter.port; + + if (bind(limiter.udp_socket, (struct sockaddr *) &server_address, sizeof(server_address)) < 0) { + printlog(LOG_CRITICAL, "Failed to bind UDP socket.\n"); + return false; + } + + printlog(LOG_WARN, " POLICY: %s\n",policy.u.string); + if (strcasecmp(policy.u.string,"GRD") == 0) { + limiter.policynum = POLICY_GRD; + } else if (strcasecmp(policy.u.string,"FPS") == 0) { + limiter.policynum = POLICY_FPS; + } else { + printlog(LOG_CRITICAL, + "Unknown DRL policy %s, aborting.\n",policy.u.string); + return (false); + } + + limiter.estintms = estintms.u.value; + if (limiter.estintms > 1000) { + printlog(LOG_CRITICAL, + "DRL: sorry estimate intervals must be less than 1 second."); + printlog(LOG_CRITICAL, + " Simple source mods will allow larger intervals. Using 1 second.\n"); + limiter.estintms = 1000; + } + printlog(LOG_WARN, " Est interval: %dms\n",limiter.estintms); + + /* Acquire the big limiter lock for writing. Prevents pretty much + * anything else from happening while the hierarchy is being changed. */ + pthread_rwlock_wrlock(&limiter.limiter_lock); + + limiter.stable_instance.ident_map = allocate_map(); + if (limiter.stable_instance.ident_map == NULL) { + printlog(LOG_CRITICAL, "Failed to allocate memory for identity map.\n"); + return false; + } + + if (get_eligible_leaves(&limiter.stable_instance)) { + printlog(LOG_CRITICAL, "Failed to read eligigle leaves.\n"); + return false; + } + + if (parse_drl_config(drl_configfile.u.string, &configs)) { + /* Parse error occured. Return non-zero to notify init_drl(). */ + return false; + } + + /* Validate identity hierarchy! */ + if (validate_configs(configs, &limiter.stable_instance)) { + /* Clean up everything. */ + free_failed_config(configs, &limiter.stable_instance); + return false; + } + + if (init_identities(configs, &limiter.stable_instance)) { + free_failed_config(configs, &limiter.stable_instance); + return false; + } + + /* At this point, we should be done with configs. */ + free_ident_list(configs.machines); + free_ident_list(configs.sets); + + /* Debugging - FIXME: remove this? */ + print_instance(&limiter.stable_instance); + + if (assign_htb_hierarchy(&limiter.stable_instance)) { + free_instance(&limiter.stable_instance); + return false; + } + + if (create_htb_hierarchy(&limiter.stable_instance)) { + free_instance(&limiter.stable_instance); + return false; + } + + pthread_rwlock_unlock(&limiter.limiter_lock); + + if (pthread_create(&limiter.udp_recv_thread, NULL, limiter_receive_thread, NULL)) { + printlog(LOG_CRITICAL, "Unable to start UDP receive thread.\n"); + return false; + } + + printlog(LOG_WARN, "ulogd_DRL init finished.\n"); + + return true; +} + +static void reconfig() { + parsed_configs configs; + + printlog(LOG_DEBUG, "--Starting reconfig()--\n"); + flushlog(); + + memset(&configs, 0, sizeof(parsed_configs)); + memset(&limiter.new_instance, 0, sizeof(drl_instance_t)); + + limiter.new_instance.ident_map = allocate_map(); + if (limiter.new_instance.ident_map == NULL) { + printlog(LOG_CRITICAL, "Failed to allocate ident_map during reconfig().\n"); + return; + } + + if (get_eligible_leaves(&limiter.new_instance)) { + free_failed_config(configs, &limiter.new_instance); + printlog(LOG_CRITICAL, "Failed to read leaves during reconfig().\n"); + return; + } + + if (parse_drl_config(drl_configfile.u.string, &configs)) { + free_failed_config(configs, &limiter.new_instance); + printlog(LOG_CRITICAL, "Failed to parse config during reconfig().\n"); + return; + } + + /* Lock */ + pthread_rwlock_wrlock(&limiter.limiter_lock); + + if (validate_configs(configs, &limiter.new_instance)) { + free_failed_config(configs, &limiter.new_instance); + printlog(LOG_CRITICAL, "Validation failed during reconfig().\n"); + pthread_rwlock_unlock(&limiter.limiter_lock); + return; + } + + if (init_identities(configs, &limiter.new_instance)) { + free_failed_config(configs, &limiter.new_instance); + printlog(LOG_CRITICAL, "Initialization failed during reconfig().\n"); + pthread_rwlock_unlock(&limiter.limiter_lock); + return; + } + + free_ident_list(configs.machines); + free_ident_list(configs.sets); + + /* Debugging - FIXME: remove this? */ + print_instance(&limiter.new_instance); + + if (assign_htb_hierarchy(&limiter.new_instance)) { + free_instance(&limiter.new_instance); + printlog(LOG_CRITICAL, "Failed to assign HTB hierarchy during reconfig().\n"); + pthread_rwlock_unlock(&limiter.limiter_lock); + return; + } + + if (create_htb_hierarchy(&limiter.new_instance)) { + free_instance(&limiter.new_instance); + printlog(LOG_CRITICAL, "Failed to create HTB hierarchy during reconfig().\n"); + + /* Re-create old instance. */ + if (create_htb_hierarchy(&limiter.stable_instance)) { + /* Error reinstating the old one - big problem. */ + printlog(LOG_CRITICAL, "Failed to reinstate HTB hierarchy during reconfig().\n"); + flushlog(); + exit(EXIT_FAILURE); + } + + pthread_rwlock_unlock(&limiter.limiter_lock); + return; + } + + /* Switch over new to stable instance. */ + free_instance(&limiter.stable_instance); + memcpy(&limiter.stable_instance, &limiter.new_instance, sizeof(drl_instance_t)); + + /* Success! - Unlock */ + pthread_rwlock_unlock(&limiter.limiter_lock); +} + +static ulog_output_t drl_op = { + .name = "drl", + .output = &_output_drl, + .signal = NULL, /* This appears to be broken. Using my own handler. */ + .init = NULL, + .fini = NULL, +}; + +/* Tests the amount of time it takes to call reconfig(). */ +static void time_reconfig(int iterations) { + struct timeval start, end; + int i; + + gettimeofday(&start, NULL); + for (i = 0; i < iterations; ++i) { + reconfig(); + } + gettimeofday(&end, NULL); + + printf("%d reconfigs() took %d seconds and %d microseconds.\n", + iterations, end.tv_sec - start.tv_sec, end.tv_usec - start.tv_usec); + exit(0); + + // Seems to take about 85ms / iteration +} + +static void *signal_thread_func(void *args) { + int sig; + int err; + sigset_t sigs; + + sigemptyset(&sigs); + sigaddset(&sigs, SIGHUP); + pthread_sigmask(SIG_BLOCK, &sigs, NULL); + + while (1) { + sigemptyset(&sigs); + sigaddset(&sigs, SIGHUP); + + err = sigwait(&sigs, &sig); + + if (err) { + printlog(LOG_CRITICAL, "sigwait() returned an error.\n"); + flushlog(); + } + + switch (sig) { + case SIGHUP: + printlog(LOG_WARN, "Caught SIGHUP - re-reading XML file.\n"); + reconfig(); + //time_reconfig(1000); //instrumentation + flushlog(); + break; + default: + /* Should be impossible... */ + break; + } + } + +} + +/* register output plugin with ulogd */ +static void _drl_reg_op(void) +{ + ulog_output_t *op = &drl_op; + sigset_t signal_mask; + + sigemptyset(&signal_mask); + sigaddset(&signal_mask, SIGHUP); + pthread_sigmask(SIG_BLOCK, &signal_mask, NULL); + + if (pthread_create(&signal_thread, NULL, &signal_thread_func, NULL) != 0) { + printlog(LOG_CRITICAL, "Failed to create signal handling thread.\n"); + fprintf(stderr, "An error has occured starting ulogd_DRL. Refer to your logfile (%s) for additional information.\n", drl_logfile.u.string); + flushlog(); + exit(EXIT_FAILURE); + } + + if (!init_drl()) { + printlog(LOG_CRITICAL, "Init failed. :(\n"); + fprintf(stderr, "An error has occured starting ulogd_DRL. Refer to your logfile (%s) for additional information.\n", drl_logfile.u.string); + flushlog(); + exit(EXIT_FAILURE); + } + + register_output(op); + + /* start up the thread that will periodically estimate the + * local rate and set the local limits + * see estimate.c + */ + if (pthread_create(&estimate_thread, NULL, (void*(*)(void*)) &handle_estimation, &limiter)!=0) { + ulogd_log(ULOGD_ERROR, "couldn't start estimate thread for 0x%x %s\n",limiter.localaddr, + limiter.ip); + fprintf(stderr, "An error has occured starting ulogd_DRL. Refer to your logfile (%s) for additional information.\n", drl_logfile.u.string); + exit(EXIT_FAILURE); + } +} + +void _init(void) +{ + /* have the opts parsed */ + config_parse_file("DRL", config_entries); + + if (get_ids()) { + ulogd_log(ULOGD_ERROR, "can't resolve all keyhash id's\n"); + exit(2); + } + + /* Seed the hash function */ + salt = getpid() ^ time(NULL); + + _drl_reg_op(); +} diff --git a/drl/util.c b/drl/util.c new file mode 100644 index 0000000..9f5706a --- /dev/null +++ b/drl/util.c @@ -0,0 +1,360 @@ +/* See the DRL-LICENSE file for this file's software license. */ + +/* util.c + * + * Mainly a hash table implementation, but other sundry items for + * ulogd_DRL as well. + * Ken Yocum 2007/08 + */ + +#include "raterouter.h" +#include "util.h" +#include "ratetypes.h" +#include "logging.h" + +static int util_salt = 0; + +/* stupidity BE:MSB first, LE: MSB last*/ +static int am_big_endian(void){ + long one = 1; + return !(*((char*)(&one))); /* looking for 1 in the big end */ +} + +static int compare_key(void *one, void *two, int len){ + int i; + for (i=0;iiterator = map->table[0]; + map->size = 0; + return(map); +} + +/* de-allocates the map, if true, de-allocates crud in map as well */ +void free_map(map_handle map, int dealloc){ + int i; + struct map_entry *nxt_me,*tmp; + for (i=0;itable[i]); + while(nxt_me) { + if (dealloc && (nxt_me->value != NULL)){ + free(nxt_me->value); + nxt_me->value=NULL; + } + tmp = nxt_me->nxt; + free(nxt_me); + map->size--; + nxt_me= tmp; + } + } + free(map); +} + +/* internal_search + * + * prior_me points to a pointer for the space holding the next map + * entry + * If you find the first entry of the linked list, it points to the + * memory in the table holding the pointer to the first map entry. + * Otherwise it points to the memory in the previous map_entry that + * holds the next pointer. + * A triple pointer here, b/c we need to save the value. + */ +static struct map_entry* internal_search(map_handle map, void *key, int keylen, struct map_entry*** prior_me){ + uint32_t index; + struct map_entry *nxt_me; + + index = jhash(key,keylen,util_salt) & (GENERIC_HASH_SIZE - 1); + +#if 0 + printf("IS: KEY:"); + for(i=0;itable[index]; + *prior_me = (struct map_entry**) &(map->table[index]); + + while(nxt_me){ + if (compare_key(nxt_me->key,key,keylen)){ + return(nxt_me); + } + *prior_me = &(nxt_me->nxt); + nxt_me = nxt_me->nxt; + } + return(NULL); + +} + +void* map_next(map_handle map){ + void *val; + + if (map->iterator_row == GENERIC_HASH_SIZE){ + return(NULL); /* empty, call reset */ + } + /* iterator points to current one to return */ + if (map->iterator != NULL){ + val = map->iterator->value; + map->iterator = map->iterator->nxt; + return(val); + } + /* if null, go to next row */ + while (map->iterator == NULL){ + map->iterator_row++; + if (map->iterator_row < GENERIC_HASH_SIZE) { + map->iterator = map->table[map->iterator_row]; + } else { + return(NULL); + } + } + val = map->iterator->value; + map->iterator = map->iterator->nxt; + return(val); +} + +void map_reset_iterate(map_handle map){ + map->iterator = map->table[0]; + map->iterator_row = 0; +} + +int map_size(map_handle map){ + return(map->size); +} + +void** map_to_array(map_handle map, int *length){ + void** array = (void**)malloc(sizeof(void*)*(map->size + 1)); + int i; + + *length = map->size; + map_reset_iterate(map); + for(i=0;isize;i++){ + array[i] = map_next(map); + } + array[i] = NULL; /* just in case */ + return(array); +} + +void* map_search(map_handle map,void *key, int keylen){ + struct map_entry *me,**pme; + me = internal_search(map,key,keylen,&pme); + if (me!=NULL) { + return(me->value); + } else { + return(NULL); + } +} + +void* map_remove(map_handle map,void *key, int keylen){ + struct map_entry *me,**pme; + void *rtn_val; + me = internal_search(map,key,keylen,&pme); + if (me!=NULL){ + (*pme) = me->nxt; + rtn_val = me->value; + free (me); + map->size--; + return(rtn_val); + } else { + return(NULL); + } +} + +/* the key is a void *, but we also need the length */ +void map_insert(map_handle map, void *key, int keylen, void *value) { + struct map_entry *me,**pme; + + me = internal_search(map,key,keylen,&pme); + if (me != NULL){ + printlog(LOG_WARN, "util.c: insert failed, key already present."); + return; + } + /* now pme is at the end of the list on that index */ + me = (struct map_entry*) malloc(sizeof(struct map_entry)); + if (me == NULL) { + printlog(LOG_WARN, "util.c: insert failed, malloc failure"); + return; + } + if ((*pme) == NULL) + (*pme) = me; /* pointer now points to this new entry */ + else { + printlog(LOG_WARN, "util.c: insert failed. pme should always be NULL."); + free(me); + return; + } + me->nxt = NULL; + me->key = key; + me->value = value; + map->size++; + return; +} + +/* get_local_ip + * + * go through the available interfaces and find the first + * with a routable IP (not 10.*, 192.*, or 172.*) + * Ignore inet6 addrs for now. + * return the string. + */ +char* get_local_ip(){ + char *ip; + struct ifaddrs *ifa = NULL, *ifp = NULL; + struct sockaddr *addr; + uint32_t ho_addr; + socklen_t salen; + int shift; + unsigned char addrbyte; + + + if (getifaddrs(&ifp) < 0) { + perror("getifaddrs"); + return 0; + } + + if (am_big_endian()){ + shift = 0; + } else { + shift = 3; + } + +#define STRINGSIZE 200 + ip = (char *)malloc(STRINGSIZE); + + + for (ifa = ifp; ifa; ifa=ifa->ifa_next){ + if (ifa->ifa_addr->sa_family == AF_INET){ + salen = sizeof(struct sockaddr_in); + } else if( ifa->ifa_addr->sa_family == AF_INET6){ + salen = sizeof(struct sockaddr_in6); + } else { + continue; + } + + + if (getnameinfo(ifa->ifa_addr,salen, ip, STRINGSIZE, NULL, 0, NI_NUMERICHOST) < 0){ + perror("getnameinfo"); + continue; + } + /* return the first public IP match */ + + addr = ifa->ifa_addr; /* a sockaddr */ + struct in_addr *sin_addr = & (((struct sockaddr_in*)addr)->sin_addr); + ho_addr = ntohl((uint32_t)(sin_addr->s_addr)); + addrbyte = ((char*)&ho_addr)[shift]; + //printf("get_local_ip found %s and sin_addr 0x%x addrbyte %d\n",ip,ho_addr,(uint32_t)addrbyte); + + /* is it MSB first? */ + + if ( (addrbyte != 192) && (addrbyte != 172) + && (addrbyte != 10) && (addrbyte != 127) ){ + printlog(LOG_WARN, " Using ip: %s\n",ip); + freeifaddrs(ifp); +#if 0 + return (ifa->ifa_addr->sin_addr); +#else + return(ip); /* for now return the IP address */ +#endif + } + } + freeifaddrs(ifp); + free(ip); + return(NULL); +} + +static FILE *urandfd = NULL; + +static void myrand_init() { + if (urandfd == NULL) { + urandfd = fopen("/dev/urandom", "rb"); + if (urandfd == NULL) { + perror("myrand_init: fopen"); + } + setvbuf(urandfd, NULL, _IOFBF, 1 << 16); + } +} + +/* returns an unsigned int between 0 and UINT_MAX */ +unsigned int myrand() { + int successful; + + /* my new rand code */ + myrand_init(); + + unsigned int r; + successful = fread(&r, sizeof(unsigned int), 1, urandfd); + + return r; +} + +/* returns a random bool */ +int myrand_boolean() { + int successful; + + myrand_init(); + + uint8_t r; + successful = fread(&r, sizeof(uint8_t), 1, urandfd); + + return (r%2); +} + +/* returns a random double between 0 and 1 */ +double myrand_double() { + return (double) myrand() / (double) UINT_MAX; +} + +/* takes the log_2 of x */ +int my_lg(int x) { + int c = 0; + while (x > 0) { + c++; + x = x >> 1; + } + + return c; +} + +/* print out some error information if a system call failes */ +void print_system_error(int ret){ + if (WIFSIGNALED(ret) && + (WTERMSIG(ret) == SIGINT || WTERMSIG(ret) == SIGQUIT)){ + /* received some kind of signal during program execution */ + printf("enforce received signal during program execution."); + } else { + perror("enforce failed (ret==-1):"); + } +} diff --git a/drl/util.h b/drl/util.h new file mode 100644 index 0000000..ffe3321 --- /dev/null +++ b/drl/util.h @@ -0,0 +1,63 @@ +/* See the DRL-LICENSE file for this file's software license. */ + +#ifndef _UTIL_H_ +#define _UTIL_H_ + +#define _XOPEN_SOURCE 600 /* for pthread_rwlock_t */ + +/* + * Jenkins hash support + */ +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +#include + +#define MAP_KEY_SIZE 4 /* all 4 bytes for now */ +#define GENERIC_HASH_SIZE 16 /* must be powers of 2 */ + +enum bool {false=0,true}; + +struct map{ + struct map_entry *table[GENERIC_HASH_SIZE]; + int iterator_row; + struct map_entry *iterator; + int size; +}; + +struct map_entry { + struct map_entry *nxt; + char *key; + void *value; +}; + +/* typedef's */ +typedef struct map *map_handle; + +/* function prototypes */ + +char* get_local_ip(); + +void ip_from_bytes(uint32_t addr, char *buf); +uint32_t myrand(); +int myrand_boolean(); +double myrand_double(); +int my_lg(int x); + +/* hash map interface */ +void init_hashing(void); +map_handle allocate_map(void); +void free_map(map_handle map, int dealloc); +void** map_to_array(map_handle map, int *length); +void* map_search(map_handle map,void *key, int keylen); +void map_reset_iterate(map_handle map); +void* map_next(map_handle table); +void* map_remove(map_handle map,void *key, int keylen); +void map_insert(map_handle map, void *key, int keylen, void *value); +int map_size(map_handle map); + +/* sundry items */ +void print_system_error(int ret); + + +#endif diff --git a/extensions/Makefile.in b/extensions/Makefile.in new file mode 100644 index 0000000..589bf7b --- /dev/null +++ b/extensions/Makefile.in @@ -0,0 +1,37 @@ +# + +# Normally You should not need to change anything below +# +include @top_srcdir@/Rules.make + +CFLAGS+=-I@top_srcdir@ -I@top_srcdir@/libipulog/include -I@top_srcdir@/include +SH_CFLAGS:=$(CFLAGS) -fPIC + +SHARED_LIBS+=$(foreach T,$(ULOGD_SL),ulogd_$(T).so) + + +all: $(SHARED_LIBS) + +distrib: + +printpkt.o: printpkt.c + $(CC) $(SH_CFLAGS) -o $@ -c $< + +$(SHARED_LIBS): %.so: %_sh.o + $(LD) -shared -o $@ $< -lc + +ulogd_SYSLOG.so: printpkt.o ulogd_SYSLOG_sh.o + $(LD) -shared -o $@ $^ -lc + +%_sh.o: %.c + $(CC) $(SH_CFLAGS) -o $@ -c $< + +clean: + $(RM) $(SHARED_LIBS) *.o + +distclean: + $(RM) Makefile + +install: all + $(INSTALL) -m 755 -d $(DESTDIR)$(ULOGD_LIB_PATH) + $(INSTALL) -m 755 *.so $(DESTDIR)$(ULOGD_LIB_PATH) diff --git a/extensions/chtons.h b/extensions/chtons.h new file mode 100644 index 0000000..4506e33 --- /dev/null +++ b/extensions/chtons.h @@ -0,0 +1,32 @@ +#ifndef _CHTONS_H_ +#define _CHTONS_H_ + +#include + +#if __BYTE_ORDER == __BIG_ENDIAN +# define BITNR(X) ((X)^31) +# if !defined(__constant_htonl) +# define __constant_htonl(x) (x) +# endif +# if !defined(__constant_htons) +# define __constant_htons(x) (x) +# endif +#elif __BYTE_ORDER == __LITTLE_ENDIAN +# define BITNR(X) ((X)^7) +# if !defined(__constant_htonl) +# define __constant_htonl(x) \ + ((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \ + (((unsigned long int)(x) & 0x0000ff00U) << 8) | \ + (((unsigned long int)(x) & 0x00ff0000U) >> 8) | \ + (((unsigned long int)(x) & 0xff000000U) >> 24))) +# endif +# if !defined(__constant_htons) +# define __constant_htons(x) \ + ((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \ + (((unsigned short int)(x) & 0xff00) >> 8))) +# endif +#else +# error "Don't know if bytes are big- or little-endian!" +#endif + +#endif diff --git a/extensions/printpkt.c b/extensions/printpkt.c new file mode 100644 index 0000000..a2558ec --- /dev/null +++ b/extensions/printpkt.c @@ -0,0 +1,275 @@ +/* printpkt.c + * + * build something looking like a iptables LOG message + * + * (C) 2000-2003 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: printpkt.c 6432 2006-01-25 11:21:28Z /C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org $ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef HOST_NAME_MAX +#warning this libc does not define HOST_NAME_MAX +#define HOST_NAME_MAX (255+1) +#endif + +#define NIPQUAD(addr) \ + ((unsigned char *)&addr)[0], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[3] + +struct intr_id { + char* name; + unsigned int id; +}; + +static char hostname[HOST_NAME_MAX+1]; + +#define INTR_IDS 35 +static struct intr_id intr_ids[INTR_IDS] = { + { "oob.time.sec", 0 }, + { "oob.prefix", 0 }, + { "oob.in", 0 }, + { "oob.out", 0 }, + { "raw.mac", 0 }, + { "ip.saddr", 0 }, + { "ip.daddr", 0 }, + { "ip.totlen", 0 }, + { "ip.tos", 0 }, + { "ip.ttl", 0 }, + { "ip.id", 0 }, + { "ip.fragoff", 0 }, + { "ip.protocol", 0 }, + { "tcp.sport", 0 }, + { "tcp.dport", 0 }, + { "tcp.seq", 0 }, + { "tcp.ackseq", 0 }, + { "tcp.window", 0 }, + { "tcp.urg", 0 }, + { "tcp.ack", 0 }, + { "tcp.psh", 0 }, + { "tcp.rst", 0 }, + { "tcp.syn", 0 }, + { "tcp.fin", 0 }, + { "tcp.urgp", 0 }, + { "udp.sport", 0 }, + { "udp.dport", 0 }, + { "udp.len", 0 }, + { "icmp.type", 0 }, + { "icmp.code", 0 }, + { "icmp.echoid", 0 }, + { "icmp.echoseq", 0 }, + { "icmp.gateway", 0 }, + { "icmp.fragmtu", 0 }, + { "ahesp.spi", 0 }, +}; + +#define GET_VALUE(x) ulogd_keyh[intr_ids[x].id].interp->result[ulogd_keyh[intr_ids[x].id].offset].value +#define GET_FLAGS(x) ulogd_keyh[intr_ids[x].id].interp->result[ulogd_keyh[intr_ids[x].id].offset].flags + +int printpkt_print(ulog_iret_t *res, char *buf, int prefix) +{ + char *timestr; + char *tmp; + time_t now; + + char *buf_cur = buf; + + if (prefix) { + now = (time_t) GET_VALUE(0).ui32; + timestr = ctime(&now) + 4; + + /* truncate time */ + if ((tmp = strchr(timestr, '\n'))) + *tmp = '\0'; + + /* truncate hostname */ + if ((tmp = strchr(hostname, '.'))) + *tmp = '\0'; + + /* print time and hostname */ + buf_cur += sprintf(buf_cur, "%.15s %s", timestr, hostname); + } + + if (*(char *) GET_VALUE(1).ptr) + buf_cur += sprintf(buf_cur, " %s", (char *) GET_VALUE(1).ptr); + + buf_cur += sprintf(buf_cur," IN=%s OUT=%s ", + (char *) GET_VALUE(2).ptr, + (char *) GET_VALUE(3).ptr); + + /* FIXME: configurable */ + buf_cur += sprintf(buf_cur, "MAC=%s ", + (GET_FLAGS(4) & ULOGD_RETF_VALID) ? (char *) GET_VALUE(4).ptr : ""); + + buf_cur += sprintf(buf_cur, "SRC=%s ", + inet_ntoa((struct in_addr) {htonl(GET_VALUE(5).ui32)})); + buf_cur += sprintf(buf_cur, "DST=%s ", + inet_ntoa((struct in_addr) {htonl(GET_VALUE(6).ui32)})); + + buf_cur += sprintf(buf_cur,"LEN=%u TOS=%02X PREC=0x%02X TTL=%u ID=%u ", + GET_VALUE(7).ui16, GET_VALUE(8).ui8 & IPTOS_TOS_MASK, + GET_VALUE(8).ui8 & IPTOS_PREC_MASK, GET_VALUE(9).ui8, + GET_VALUE(10).ui16); + + if (GET_VALUE(10).ui16 & IP_RF) + buf_cur += sprintf(buf_cur, "CE "); + + if (GET_VALUE(11).ui16 & IP_DF) + buf_cur += sprintf(buf_cur, "DF "); + + if (GET_VALUE(11).ui16 & IP_MF) + buf_cur += sprintf(buf_cur, "MF "); + + if (GET_VALUE(11).ui16 & IP_OFFMASK) + buf_cur += sprintf(buf_cur, "FRAG:%u ", + GET_VALUE(11).ui16 & IP_OFFMASK); + + switch (GET_VALUE(12).ui8) { + + case IPPROTO_TCP: + buf_cur += sprintf(buf_cur, "PROTO=TCP "); + buf_cur += sprintf(buf_cur, "SPT=%u DPT=%u ", + GET_VALUE(13).ui16, GET_VALUE(14).ui16); + /* FIXME: config */ + buf_cur += sprintf(buf_cur, "SEQ=%u ACK=%u ", + GET_VALUE(15).ui32, GET_VALUE(16).ui32); + + buf_cur += sprintf(buf_cur, "WINDOW=%u ", GET_VALUE(17).ui16); + +// buf_cur += sprintf(buf_cur, "RES=0x%02x ", + + if (GET_VALUE(18).b) + buf_cur += sprintf(buf_cur, "URG "); + + if (GET_VALUE(19).b) + buf_cur += sprintf(buf_cur, "ACK "); + + if (GET_VALUE(20).b) + buf_cur += sprintf(buf_cur, "PSH "); + + if (GET_VALUE(21).b) + buf_cur += sprintf(buf_cur, "RST "); + + if (GET_VALUE(22).b) + buf_cur += sprintf(buf_cur, "SYN "); + + if (GET_VALUE(23).b) + buf_cur += sprintf(buf_cur, "FIN "); + + buf_cur += sprintf(buf_cur, "URGP=%u ", GET_VALUE(24).ui16); + + break; + case IPPROTO_UDP: + + buf_cur += sprintf(buf_cur, "PROTO=UDP "); + + buf_cur += sprintf(buf_cur, "SPT=%u DPT=%u LEN=%u ", + GET_VALUE(25).ui16, GET_VALUE(26).ui16, + GET_VALUE(27).ui16); + break; + case IPPROTO_ICMP: + + buf_cur += sprintf(buf_cur, "PROTO=ICMP "); + + buf_cur += sprintf(buf_cur, "TYPE=%u CODE=%u ", + GET_VALUE(28).ui8, GET_VALUE(29).ui8); + + switch (GET_VALUE(28).ui8) { + case ICMP_ECHO: + case ICMP_ECHOREPLY: + buf_cur += sprintf(buf_cur, "ID=%u SEQ=%u ", + GET_VALUE(30).ui16, + GET_VALUE(31).ui16); + break; + case ICMP_PARAMETERPROB: + buf_cur += sprintf(buf_cur, "PARAMETER=%u ", + GET_VALUE(32).ui32 >> 24); + break; + case ICMP_REDIRECT: + buf_cur += sprintf(buf_cur, "GATEWAY=%s ", inet_ntoa((struct in_addr) {htonl(GET_VALUE(32).ui32)})); + break; + case ICMP_DEST_UNREACH: + if (GET_VALUE(29).ui8 == ICMP_FRAG_NEEDED) + buf_cur += sprintf(buf_cur, "MTU=%u ", + GET_VALUE(33).ui16); + break; + } + break; + case IPPROTO_ESP: + case IPPROTO_AH: + buf_cur += sprintf(buf_cur, "PROTO=%s ", GET_VALUE(12).ui8 == IPPROTO_ESP ? "ESP" : "AH"); + /* FIXME: "INCOMPLETE [%u bytes]" in case of short pkt */ + if (intr_ids[34].id > 0) { + buf_cur += sprintf(buf_cur, "SPI=0x%x ", GET_VALUE(34).ui32); + } + break; + default: + + buf_cur += sprintf(buf_cur, "PROTO=%u ", GET_VALUE(12).ui8); + } + strcat(buf_cur, "\n"); + + return 0; +} + +/* get all key id's for the keys we are intrested in */ +static int get_ids(void) +{ + int i; + struct intr_id *cur_id; + + for (i = 0; i < INTR_IDS; i++) { + cur_id = &intr_ids[i]; + cur_id->id = keyh_getid(cur_id->name); + if (!cur_id->id) { + ulogd_log(ULOGD_ERROR, + "Cannot resolve keyhash id for %s\n", + cur_id->name); + return 1; + } + } + return 0; +} + +int printpkt_init(void) +{ + if (gethostname(hostname, sizeof(hostname)) < 0) { + ulogd_log(ULOGD_FATAL, "can't gethostname(): %s\n", + strerror(errno)); + exit(2); + } + + if (get_ids()) + return 1; + + return 0; +} diff --git a/extensions/printpkt.h b/extensions/printpkt.h new file mode 100644 index 0000000..ce42de4 --- /dev/null +++ b/extensions/printpkt.h @@ -0,0 +1,7 @@ +#ifndef _PRINTPKT_H +#define _PRINTPKT_H + +int printpkt_print(ulog_iret_t *res, char *buf, int prefix); +int printpkt_init(void); + +#endif diff --git a/extensions/ulogd_BASE.c b/extensions/ulogd_BASE.c new file mode 100644 index 0000000..646f55f --- /dev/null +++ b/extensions/ulogd_BASE.c @@ -0,0 +1,669 @@ +/* ulogd_MAC.c, Version $Revision: 5239 $ + * + * ulogd interpreter plugin for + * o MAC addresses + * o NFMARK field + * o TIME + * o Interface names + * o IP header + * o TCP header + * o UDP header + * o ICMP header + * o AH/ESP header + * o GRE header + * + * (C) 2000-2001 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * $Id: ulogd_BASE.c 5239 2005-02-12 21:22:56Z laforge $ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*********************************************************************** + * Raw header + ***********************************************************************/ +static ulog_iret_t raw_rets[] = { + { .type = ULOGD_RET_STRING, + .flags = ULOGD_RETF_FREE, + .key = "raw.mac", + }, + { .type = ULOGD_RET_RAW, + .flags = ULOGD_RETF_NONE, + .key = "raw.pkt", + }, + { .type = ULOGD_RET_UINT32, + .flags = ULOGD_RETF_NONE, + .key = "raw.pktlen", + }, +}; + +static ulog_iret_t *_interp_raw(ulog_interpreter_t *ip, + ulog_packet_msg_t *pkt) +{ + unsigned char *p; + int i; + char *buf, *oldbuf = NULL; + ulog_iret_t *ret = ip->result; + + if (pkt->mac_len) { + buf = (char *) malloc(3 * pkt->mac_len + 1); + if (!buf) { + ulogd_log(ULOGD_ERROR, "OOM!!!\n"); + return NULL; + } + *buf = '\0'; + + p = pkt->mac; + oldbuf = buf; + for (i = 0; i < pkt->mac_len; i++, p++) + sprintf(buf, "%s%02x%c", oldbuf, *p, i==pkt->mac_len-1 ? ' ':':'); + ret[0].value.ptr = buf; + ret[0].flags |= ULOGD_RETF_VALID; + } + + /* include pointer to raw ipv4 packet */ + ret[1].value.ptr = pkt->payload; + ret[1].flags |= ULOGD_RETF_VALID; + ret[2].value.ui32 = pkt->data_len; + ret[2].flags |= ULOGD_RETF_VALID; + + return ret; +} + +/*********************************************************************** + * OUT OF BAND + ***********************************************************************/ + +static ulog_iret_t oob_rets[] = { + { .type = ULOGD_RET_STRING, + .flags = ULOGD_RETF_NONE, + .key = "oob.prefix", + }, + { .type = ULOGD_RET_UINT32, + .flags = ULOGD_RETF_NONE, + .key = "oob.time.sec", + }, + { .type = ULOGD_RET_UINT32, + .flags = ULOGD_RETF_NONE, + .key = "oob.time.usec", + }, + { .type = ULOGD_RET_UINT32, + .flags = ULOGD_RETF_NONE, + .key = "oob.mark", + }, + { .type = ULOGD_RET_STRING, + .flags = ULOGD_RETF_NONE, + .key = "oob.in", + }, + { .type = ULOGD_RET_STRING, + .flags = ULOGD_RETF_NONE, + .key = "oob.out", + }, +}; + +static ulog_iret_t *_interp_oob(struct ulog_interpreter *ip, + ulog_packet_msg_t *pkt) +{ + ulog_iret_t *ret = ip->result; + + ret[0].value.ptr = pkt->prefix; + ret[0].flags |= ULOGD_RETF_VALID; + + /* god knows why timestamp_usec contains crap if timestamp_sec == 0 + * if (pkt->timestamp_sec || pkt->timestamp_usec) { */ + if (pkt->timestamp_sec) { + ret[1].value.ui32 = pkt->timestamp_sec; + ret[1].flags |= ULOGD_RETF_VALID; + ret[2].value.ui32 = pkt->timestamp_usec; + ret[2].flags |= ULOGD_RETF_VALID; + } else { + ret[1].flags &= ~ULOGD_RETF_VALID; + ret[2].flags &= ~ULOGD_RETF_VALID; + } + + ret[3].value.ui32 = pkt->mark; + ret[3].flags |= ULOGD_RETF_VALID; + ret[4].value.ptr = pkt->indev_name; + ret[4].flags |= ULOGD_RETF_VALID; + ret[5].value.ptr = pkt->outdev_name; + ret[5].flags |= ULOGD_RETF_VALID; + + return ret; +} + +/*********************************************************************** + * IP HEADER + ***********************************************************************/ + +static ulog_iret_t iphdr_rets[] = { + { .type = ULOGD_RET_IPADDR, + .flags = ULOGD_RETF_NONE, + .key = "ip.saddr", + }, + { .type = ULOGD_RET_IPADDR, + .flags = ULOGD_RETF_NONE, + .key = "ip.daddr", + }, + { .type = ULOGD_RET_UINT8, + .flags = ULOGD_RETF_NONE, + .key = "ip.protocol", + }, + { .type = ULOGD_RET_UINT8, + .flags = ULOGD_RETF_NONE, + .key = "ip.tos", + }, + { .type = ULOGD_RET_UINT8, + .flags = ULOGD_RETF_NONE, + .key = "ip.ttl", + }, + { .type = ULOGD_RET_UINT16, + .flags = ULOGD_RETF_NONE, + .key = "ip.totlen", + }, + { .type = ULOGD_RET_UINT8, + .flags = ULOGD_RETF_NONE, + .key = "ip.ihl", + }, + { .type = ULOGD_RET_UINT16, + .flags = ULOGD_RETF_NONE, + .key = "ip.csum", + }, + { .type = ULOGD_RET_UINT16, + .flags = ULOGD_RETF_NONE, + .key = "ip.id", + }, + { .type = ULOGD_RET_UINT16, + .flags = ULOGD_RETF_NONE, + .key = "ip.fragoff", + }, +}; + +static ulog_iret_t *_interp_iphdr(struct ulog_interpreter *ip, + ulog_packet_msg_t *pkt) +{ + ulog_iret_t *ret = ip->result; + struct iphdr *iph = (struct iphdr *) pkt->payload; + + ret[0].value.ui32 = ntohl(iph->saddr); + ret[0].flags |= ULOGD_RETF_VALID; + ret[1].value.ui32 = ntohl(iph->daddr); + ret[1].flags |= ULOGD_RETF_VALID; + ret[2].value.ui8 = iph->protocol; + ret[2].flags |= ULOGD_RETF_VALID; + ret[3].value.ui8 = iph->tos; + ret[3].flags |= ULOGD_RETF_VALID; + ret[4].value.ui8 = iph->ttl; + ret[4].flags |= ULOGD_RETF_VALID; + ret[5].value.ui16 = ntohs(iph->tot_len); + ret[5].flags |= ULOGD_RETF_VALID; + ret[6].value.ui8 = iph->ihl; + ret[6].flags |= ULOGD_RETF_VALID; + ret[7].value.ui16 = ntohs(iph->check); + ret[7].flags |= ULOGD_RETF_VALID; + ret[8].value.ui16 = ntohs(iph->id); + ret[8].flags |= ULOGD_RETF_VALID; + ret[9].value.ui16 = ntohs(iph->frag_off); + ret[9].flags |= ULOGD_RETF_VALID; + + return ret; +} + +/*********************************************************************** + * TCP HEADER + ***********************************************************************/ +static ulog_iret_t tcphdr_rets[] = { + { .type = ULOGD_RET_UINT16, + .flags = ULOGD_RETF_NONE, + .key = "tcp.sport", + }, + { .type = ULOGD_RET_UINT16, + .flags = ULOGD_RETF_NONE, + .key = "tcp.dport", + }, + { .type = ULOGD_RET_UINT32, + .flags = ULOGD_RETF_NONE, + .key = "tcp.seq", + }, + { .type = ULOGD_RET_UINT32, + .flags = ULOGD_RETF_NONE, + .key = "tcp.ackseq", + }, + { .type = ULOGD_RET_UINT8, + .flags = ULOGD_RETF_NONE, + .key = "tcp.offset", + }, + { .type = ULOGD_RET_UINT8, + .flags = ULOGD_RETF_NONE, + .key = "tcp.reserved", + }, + { .type = ULOGD_RET_UINT16, + .flags = ULOGD_RETF_NONE, + .key = "tcp.window", + }, + { .type = ULOGD_RET_BOOL, + .flags = ULOGD_RETF_NONE, + .key = "tcp.urg", + }, + { .type = ULOGD_RET_UINT16, + .flags = ULOGD_RETF_NONE, + .key = "tcp.urgp", + }, + { .type = ULOGD_RET_BOOL, + .flags = ULOGD_RETF_NONE, + .key = "tcp.ack", + }, + { .type = ULOGD_RET_BOOL, + .flags = ULOGD_RETF_NONE, + .key = "tcp.psh", + }, + { .type = ULOGD_RET_BOOL, + .flags = ULOGD_RETF_NONE, + .key = "tcp.rst", + }, + { .type = ULOGD_RET_BOOL, + .flags = ULOGD_RETF_NONE, + .key = "tcp.syn", + }, + { .type = ULOGD_RET_BOOL, + .flags = ULOGD_RETF_NONE, + .key = "tcp.fin", + }, + { .type = ULOGD_RET_BOOL, + .flags = ULOGD_RETF_NONE, + .key = "tcp.res1", + }, + { .type = ULOGD_RET_BOOL, + .flags = ULOGD_RETF_NONE, + .key = "tcp.res2", + }, + { .type = ULOGD_RET_UINT16, + .flags = ULOGD_RETF_NONE, + .key = "tcp.csum", + }, +}; + +static ulog_iret_t *_interp_tcphdr(struct ulog_interpreter *ip, + ulog_packet_msg_t *pkt) +{ + struct iphdr *iph = (struct iphdr *) pkt->payload; + void *protoh = (u_int32_t *)iph + iph->ihl; + struct tcphdr *tcph = (struct tcphdr *) protoh; + ulog_iret_t *ret = ip->result; + + if (iph->protocol != IPPROTO_TCP) + return NULL; + + ret[0].value.ui16 = ntohs(tcph->source); + ret[0].flags |= ULOGD_RETF_VALID; + ret[1].value.ui16 = ntohs(tcph->dest); + ret[1].flags |= ULOGD_RETF_VALID; + ret[2].value.ui32 = ntohl(tcph->seq); + ret[2].flags |= ULOGD_RETF_VALID; + ret[3].value.ui32 = ntohl(tcph->ack_seq); + ret[3].flags |= ULOGD_RETF_VALID; + ret[4].value.ui8 = ntohs(tcph->doff); + ret[4].flags |= ULOGD_RETF_VALID; + ret[5].value.ui8 = ntohs(tcph->res1); + ret[5].flags |= ULOGD_RETF_VALID; + ret[6].value.ui16 = ntohs(tcph->window); + ret[6].flags |= ULOGD_RETF_VALID; + + ret[7].value.b = tcph->urg; + ret[7].flags |= ULOGD_RETF_VALID; + if (tcph->urg) { + ret[8].value.ui16 = ntohs(tcph->urg_ptr); + ret[8].flags |= ULOGD_RETF_VALID; + } + ret[9].value.b = tcph->ack; + ret[9].flags |= ULOGD_RETF_VALID; + ret[10].value.b = tcph->psh; + ret[10].flags |= ULOGD_RETF_VALID; + ret[11].value.b = tcph->rst; + ret[11].flags |= ULOGD_RETF_VALID; + ret[12].value.b = tcph->syn; + ret[12].flags |= ULOGD_RETF_VALID; + ret[13].value.b = tcph->fin; + ret[13].flags |= ULOGD_RETF_VALID; + ret[14].value.b = tcph->res1; + ret[14].flags |= ULOGD_RETF_VALID; + ret[15].value.b = tcph->res2; + ret[15].flags |= ULOGD_RETF_VALID; + ret[16].value.ui16 = ntohs(tcph->check); + ret[16].value.ui16 = ULOGD_RETF_VALID; + + return ret; +} + +/*********************************************************************** + * UDP HEADER + ***********************************************************************/ +static ulog_iret_t udphdr_rets[] = { + { .type = ULOGD_RET_UINT16, + .flags = ULOGD_RETF_NONE, + .key = "udp.sport", + }, + { .type = ULOGD_RET_UINT16, + .flags = ULOGD_RETF_NONE, + .key = "udp.dport", + }, + { .type = ULOGD_RET_UINT16, + .flags = ULOGD_RETF_NONE, + .key = "udp.len", + }, + { .type = ULOGD_RET_UINT16, + .flags = ULOGD_RETF_NONE, + .key = "udp.csum", + }, +}; + +static ulog_iret_t *_interp_udp(struct ulog_interpreter *ip, + ulog_packet_msg_t *pkt) +{ + struct iphdr *iph = (struct iphdr *) pkt->payload; + void *protoh = (u_int32_t *)iph + iph->ihl; + struct udphdr *udph = protoh; + ulog_iret_t *ret = ip->result; + + if (iph->protocol != IPPROTO_UDP) + return NULL; + + ret[0].value.ui16 = ntohs(udph->source); + ret[0].flags |= ULOGD_RETF_VALID; + ret[1].value.ui16 = ntohs(udph->dest); + ret[1].flags |= ULOGD_RETF_VALID; + ret[2].value.ui16 = ntohs(udph->len); + ret[2].flags |= ULOGD_RETF_VALID; + ret[3].value.ui16 = ntohs(udph->check); + ret[3].flags |= ULOGD_RETF_VALID; + + return ret; +} + +/*********************************************************************** + * ICMP HEADER + ***********************************************************************/ + +static ulog_iret_t icmphdr_rets[] = { + { .type = ULOGD_RET_UINT8, + .flags = ULOGD_RETF_NONE, + .key = "icmp.type", + }, + { .type = ULOGD_RET_UINT8, + .flags = ULOGD_RETF_NONE, + .key = "icmp.code", + }, + { .type = ULOGD_RET_UINT16, + .flags = ULOGD_RETF_NONE, + .key = "icmp.echoid", + }, + { .type = ULOGD_RET_UINT16, + .flags = ULOGD_RETF_NONE, + .key = "icmp.echoseq", + }, + { .type = ULOGD_RET_IPADDR, + .flags = ULOGD_RETF_NONE, + .key = "icmp.gateway", + }, + { .type = ULOGD_RET_UINT16, + .flags = ULOGD_RETF_NONE, + .key = "icmp.fragmtu", + }, + { .type = ULOGD_RET_UINT16, + .flags = ULOGD_RETF_NONE, + .key = "icmp.csum", + }, +}; + +static ulog_iret_t *_interp_icmp(struct ulog_interpreter *ip, + ulog_packet_msg_t *pkt) +{ + struct iphdr *iph = (struct iphdr *) pkt->payload; + void *protoh = (u_int32_t *)iph + iph->ihl; + struct icmphdr *icmph = protoh; + ulog_iret_t *ret = ip->result; + + if (iph->protocol != IPPROTO_ICMP) + return NULL; + + ret[0].value.ui8 = icmph->type; + ret[0].flags |= ULOGD_RETF_VALID; + ret[1].value.ui8 = icmph->code; + ret[1].flags |= ULOGD_RETF_VALID; + + switch(icmph->type) { + case ICMP_ECHO: + case ICMP_ECHOREPLY: + ret[2].value.ui16 = ntohs(icmph->un.echo.id); + ret[2].flags |= ULOGD_RETF_VALID; + ret[3].value.ui16 = ntohs(icmph->un.echo.sequence); + ret[3].flags |= ULOGD_RETF_VALID; + break; + case ICMP_REDIRECT: + case ICMP_PARAMETERPROB: + ret[4].value.ui32 = ntohl(icmph->un.gateway); + ret[4].flags |= ULOGD_RETF_VALID; + break; + case ICMP_DEST_UNREACH: + if (icmph->code == ICMP_FRAG_NEEDED) { + ret[5].value.ui16 = ntohs(icmph->un.frag.mtu); + ret[5].flags |= ULOGD_RETF_VALID; + } + break; + } + ret[6].value.ui16 = icmph->checksum; + ret[6].flags |= ULOGD_RETF_VALID; + + return ret; +} + +/*********************************************************************** + * IPSEC HEADER + ***********************************************************************/ + +static ulog_iret_t ahesphdr_rets[] = { + { .type = ULOGD_RET_UINT32, + .flags = ULOGD_RETF_NONE, + .key = "ahesp.spi", + }, +}; + +static ulog_iret_t *_interp_ahesp(struct ulog_interpreter *ip, + ulog_packet_msg_t *pkt) +{ + + ulog_iret_t *ret = ip->result; +#if 0 + struct iphdr *iph = (struct iphdr *) pkt->payload; + void *protoh = (u_int32_t *) (iph + iph->ihl); + struct esphdr *esph = protoh; + + if (iph->protocol != IPPROTO_ESP) + return NULL; + + ret[0].value.ui32 = ntohl(esph->spi); + ret[0].flags |= ULOGD_RETF_VALID; +#endif + + return ret; +} + +/*********************************************************************** + * GRE/PPTP HEADER + ***********************************************************************/ + +static ulog_iret_t gre_rets[] = { + { NULL, NULL, 0, ULOGD_RET_BOOL, ULOGD_RETF_NONE, "gre.flag.csum", + { b: 0 } }, + { NULL, NULL, 0, ULOGD_RET_BOOL, ULOGD_RETF_NONE, "gre.flag.route", + { b: 0 } }, + { NULL, NULL, 0, ULOGD_RET_BOOL, ULOGD_RETF_NONE, "gre.flag.key", + { b: 0 } }, + { NULL, NULL, 0, ULOGD_RET_BOOL, ULOGD_RETF_NONE, "gre.flag.seq", + { b: 0 } }, + { NULL, NULL, 0, ULOGD_RET_BOOL, ULOGD_RETF_NONE, "gre.flag.ssr", + { b: 0 } }, + { NULL, NULL, 0, ULOGD_RET_BOOL, ULOGD_RETF_NONE, "gre.flag.recur", + { b: 0 } }, + { NULL, NULL, 0, ULOGD_RET_BOOL, ULOGD_RETF_NONE, "gre.flag.ack", + { b: 0 } }, + { NULL, NULL, 0, ULOGD_RET_UINT8, ULOGD_RETF_NONE, "gre.version", + { ui8 :0 } }, + { NULL, NULL, 0, ULOGD_RET_UINT16, ULOGD_RETF_NONE, "gre.protocol", + { ui16: 0 } }, + { NULL, NULL, 0, ULOGD_RET_UINT16, ULOGD_RETF_NONE, "gre.csum", + { ui16: 0 } }, + { NULL, NULL, 0, ULOGD_RET_UINT32, ULOGD_RETF_NONE, "gre.key", + { ui32: 0 } }, + { NULL, NULL, 0, ULOGD_RET_UINT32, ULOGD_RETF_NONE, "gre.seq", + { ui32: 0 } }, + { NULL, NULL, 0, ULOGD_RET_UINT16, ULOGD_RETF_NONE, "pptp.pktlen", + { ui16: 0 } }, + { NULL, NULL, 0, ULOGD_RET_UINT16, ULOGD_RETF_NONE, "pptp.callid", + { ui16: 0 } }, + { NULL, NULL, 0, ULOGD_RET_UINT32, ULOGD_RETF_NONE, "pptp.seq", + { ui32: 0 } }, + { NULL, NULL, 0, ULOGD_RET_UINT32, ULOGD_RETF_NONE, "pptp.ack", + { ui32: 0 } }, +}; + +static ulog_iret_t *_interp_gre(struct ulog_interpreter *ip, + ulog_packet_msg_t *pkt) +{ + struct iphdr *iph = (struct iphdr *) pkt->payload; + void *protoh = (u_int32_t *)iph + iph->ihl; + struct grehdr *greh = protoh; + struct pptphdr *pptph = protoh; + ulog_iret_t *ret = ip->result; + + if (iph->protocol != IPPROTO_GRE) + return NULL; + + ret[0].value.b = (greh->flags_ver & GRE_FLAG_CKSUM) ? 1 : 0; + ret[0].flags |= ULOGD_RETF_VALID; + ret[1].value.b = (greh->flags_ver & GRE_FLAG_ROUTE) ? 1 : 0; + ret[1].flags |= ULOGD_RETF_VALID; + ret[2].value.b = (greh->flags_ver & GRE_FLAG_KEY) ? 1 : 0; + ret[2].flags |= ULOGD_RETF_VALID; + ret[3].value.b = (greh->flags_ver & GRE_FLAG_SEQ) ? 1 : 0; + ret[3].flags |= ULOGD_RETF_VALID; + ret[4].value.b = (greh->flags_ver & GRE_FLAG_SSR) ? 1 : 0; + ret[4].flags |= ULOGD_RETF_VALID; + ret[5].value.b = (greh->flags_ver & GRE_FLAG_RECUR) ? 1 : 0; + ret[5].flags |= ULOGD_RETF_VALID; + ret[6].value.b = (greh->flags_ver & GRE_FLAG_ACK) ? 1 : 0; + ret[6].flags |= ULOGD_RETF_VALID; + ret[7].value.ui8 = (greh->flags_ver & GRE_FLAG_VER); + ret[7].flags |= ULOGD_RETF_VALID; + ret[8].value.ui16 = ntohs(greh->protocol); + ret[8].flags |= ULOGD_RETF_VALID; + + ret[9].flags &= ~ULOGD_RETF_VALID; + ret[10].flags &= ~ULOGD_RETF_VALID; + ret[11].flags &= ~ULOGD_RETF_VALID; + ret[12].flags &= ~ULOGD_RETF_VALID; + ret[13].flags &= ~ULOGD_RETF_VALID; + ret[14].flags &= ~ULOGD_RETF_VALID; + ret[15].flags &= ~ULOGD_RETF_VALID; + + if ((greh->flags_ver & GRE_FLAG_VER) == GRE_VER_GRE) { + if (greh->flags_ver & GRE_FLAG_CKSUM) { + ret[9].value.ui16 = ntohs(greh->cksum); + ret[9].flags |= ULOGD_RETF_VALID; + } + if (greh->flags_ver & GRE_FLAG_KEY) { + ret[10].value.ui32 = ntohl(greh->key); + ret[10].flags |= ULOGD_RETF_VALID; + } + if (greh->flags_ver & GRE_FLAG_SEQ) { + ret[11].value.ui32 = ntohl(greh->seq); + ret[11].flags |= ULOGD_RETF_VALID; + } + } else if ((greh->flags_ver & GRE_FLAG_VER) == GRE_VER_PPTP) { + ret[12].value.ui16 = ntohs(pptph->payload_len); + ret[12].flags |= ULOGD_RETF_VALID; + ret[13].value.ui16 = ntohs(pptph->call_id); + ret[13].flags |= ULOGD_RETF_VALID; + if (greh->flags_ver & GRE_FLAG_SEQ) { + ret[14].value.ui32 = ntohl(pptph->seq); + ret[14].flags |= ULOGD_RETF_VALID; + } + if (greh->flags_ver & GRE_FLAG_ACK) { + ret[15].value.ui32 = ntohl(pptph->ack); + ret[15].flags |= ULOGD_RETF_VALID; + } + } + + return ret; +} + + +static ulog_interpreter_t base_ip[] = { + { .name = "raw", + .interp = &_interp_raw, + .key_num = 3, + .result = raw_rets }, + { .name = "oob", + .interp = &_interp_oob, + .key_num = 6, + .result = oob_rets }, + { .name = "ip", + .interp = &_interp_iphdr, + .key_num = 10, + .result = iphdr_rets }, + { .name = "tcp", + .interp = &_interp_tcphdr, + .key_num = 17, + .result = tcphdr_rets }, + { .name = "icmp", + .interp = &_interp_icmp, + .key_num = 7, + .result = icmphdr_rets }, + { .name = "udp", + .interp = &_interp_udp, + .key_num = 4, + .result = udphdr_rets }, + { .name = "ahesp", + .interp = &_interp_ahesp, + .key_num = 1, + .result = ahesphdr_rets }, + { NULL, "gre", 0, &_interp_gre, 16, gre_rets }, + { NULL, "", 0, NULL, 0, NULL }, +}; + +void _base_reg_ip(void) +{ + ulog_interpreter_t *ip = base_ip; + ulog_interpreter_t *p; + + for (p = ip; p->interp; p++) { + register_interpreter(p); + } +} + +void _init(void) +{ + _base_reg_ip(); +} diff --git a/extensions/ulogd_LOCAL.c b/extensions/ulogd_LOCAL.c new file mode 100644 index 0000000..1004586 --- /dev/null +++ b/extensions/ulogd_LOCAL.c @@ -0,0 +1,101 @@ +/* ulogd_LOCAL.c, Version 0.3 + * + * ulogd interpreter plugin for: - local time of packet + * - hostname of localhost + * + * (C) 2001-2002 by Florent AIDE + * with the help of Moez MKADMI + * shamelessly ripped from Harald Welte + * + * 2002 extended by Martin Kaehmer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + */ + +#include +#include +#include +#include +#include + +#ifdef DEBUG_LOCAL +#define DEBUGP(x) ulogd_log(ULOGD_DEBUG, x) +#else +#define DEBUGP(format, args...) +#endif + + +static char hostname[255]; + +static ulog_iret_t *_interp_local(ulog_interpreter_t *ip, + ulog_packet_msg_t *pkt) +{ + struct timeval tv; + ulog_iret_t *ret = ip->result; + + /* Get date */ + gettimeofday(&tv, NULL); + + /* put date */ + ret[0].value.ui32 = (unsigned long) tv.tv_sec; + ret[0].flags |= ULOGD_RETF_VALID; + + ret[1].value.ptr = hostname; + ret[1].flags |= ULOGD_RETF_VALID; + + return ret; +} + +static ulog_iret_t local_rets[] = { + { .type = ULOGD_RET_UINT32, + .flags = ULOGD_RETF_NONE, + .key = "local.time", + }, + { .type = ULOGD_RET_STRING, + .flags = ULOGD_RETF_NONE, + .key = "local.hostname", + }, +}; + +static ulog_interpreter_t local_ip[] = { + { NULL, "local", 0, &_interp_local, 2, local_rets }, + { NULL, "", 0, NULL, 0, NULL }, +}; + +static void _local_reg_ip(void) +{ + ulog_interpreter_t *ip = local_ip; + ulog_interpreter_t *p; + + for (p = ip; p->interp; p++) + register_interpreter(p); +} + +void _init(void) +{ + /* get hostname */ + char *tmp; + if (gethostname(hostname, sizeof(hostname)) < 0) { + ulogd_log(ULOGD_FATAL, "can't gethostname(): %s\n", + strerror(errno)); + exit(2); + } + /* strip off everything after first '.' */ + if ((tmp = strchr(hostname, '.'))) + *tmp = '\0'; + + _local_reg_ip(); +} diff --git a/extensions/ulogd_LOGEMU.c b/extensions/ulogd_LOGEMU.c new file mode 100644 index 0000000..ed89c1c --- /dev/null +++ b/extensions/ulogd_LOGEMU.c @@ -0,0 +1,136 @@ +/* ulogd_LOGEMU.c, Version $Revision: 5252 $ + * + * ulogd output target for syslog logging emulation + * + * This target produces a file which looks the same like the syslog-entries + * of the LOG target. + * + * (C) 2000-2001 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: ulogd_LOGEMU.c 5252 2005-02-14 16:12:49Z laforge $ + * + */ + +#include +#include +#include +#include +#include +#include +#include "printpkt.c" + +#ifndef ULOGD_LOGEMU_DEFAULT +#define ULOGD_LOGEMU_DEFAULT "/var/log/ulogd.syslogemu" +#endif + +#ifndef ULOGD_LOGEMU_SYNC_DEFAULT +#define ULOGD_LOGEMU_SYNC_DEFAULT 0 +#endif + +#define NIPQUAD(addr) \ + ((unsigned char *)&addr)[0], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[3] + +static config_entry_t syslogf_ce = { + .key = "file", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_NONE, + .u = { .string = ULOGD_LOGEMU_DEFAULT } +}; + +static config_entry_t syslsync_ce = { + .next = &syslogf_ce, + .key = "sync", + .type = CONFIG_TYPE_INT, + .options = CONFIG_OPT_NONE, + .u = { .value = ULOGD_LOGEMU_SYNC_DEFAULT } +}; + +static FILE *of = NULL; + +static int _output_logemu(ulog_iret_t *res) +{ + static char buf[4096]; + + printpkt_print(res, buf, 1); + + fprintf(of, "%s", buf); + + if (syslsync_ce.u.value) + fflush(of); + + return 0; +} + +static void signal_handler_logemu(int signal) +{ + switch (signal) { + case SIGHUP: + ulogd_log(ULOGD_NOTICE, "syslogemu: reopening logfile\n"); + fclose(of); + of = fopen(syslogf_ce.u.string, "a"); + if (!of) { + ulogd_log(ULOGD_FATAL, "can't open syslogemu: %s\n", + strerror(errno)); + exit(2); + } + break; + default: + break; + } +} + + +static int init_logemu(void) { + /* FIXME: error handling */ + config_parse_file("LOGEMU", &syslsync_ce); + +#ifdef DEBUG_LOGEMU + of = stdout; +#else + of = fopen(syslogf_ce.u.string, "a"); + if (!of) { + ulogd_log(ULOGD_FATAL, "can't open syslogemu: %s\n", + strerror(errno)); + exit(2); + } +#endif + if (printpkt_init()) { + ulogd_log(ULOGD_ERROR, "can't resolve all keyhash id's\n"); + } + + return 1; +} + +static void fini_logemu(void) { + if (of != stdout) + fclose(of); +} + +static ulog_output_t logemu_op = { + .name = "syslogemu", + .init = &init_logemu, + .fini = &fini_logemu, + .output = &_output_logemu, + .signal = &signal_handler_logemu, +}; + +void _init(void) +{ + register_output(&logemu_op); +} diff --git a/extensions/ulogd_OPRINT.c b/extensions/ulogd_OPRINT.c new file mode 100644 index 0000000..429104f --- /dev/null +++ b/extensions/ulogd_OPRINT.c @@ -0,0 +1,144 @@ +/* ulogd_MAC.c, Version $Revision: 5252 $ + * + * ulogd output target for logging to a file + * + * (C) 2000-2001 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: ulogd_OPRINT.c 5252 2005-02-14 16:12:49Z laforge $ + * + */ + +#include +#include +#include +#include +#include + +#ifndef ULOGD_OPRINT_DEFAULT +#define ULOGD_OPRINT_DEFAULT "/var/log/ulogd.pktlog" +#endif + +#define NIPQUAD(addr) \ + ((unsigned char *)&addr)[0], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[3] + +#define HIPQUAD(addr) \ + ((unsigned char *)&addr)[3], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[0] + +static FILE *of = NULL; + +static int _output_print(ulog_iret_t *res) +{ + ulog_iret_t *ret; + + fprintf(of, "===>PACKET BOUNDARY\n"); + for (ret = res; ret; ret = ret->cur_next) { + fprintf(of,"%s=", ret->key); + switch (ret->type) { + case ULOGD_RET_STRING: + fprintf(of, "%s\n", (char *) ret->value.ptr); + break; + case ULOGD_RET_BOOL: + case ULOGD_RET_INT8: + case ULOGD_RET_INT16: + case ULOGD_RET_INT32: + fprintf(of, "%d\n", ret->value.i32); + break; + case ULOGD_RET_UINT8: + case ULOGD_RET_UINT16: + case ULOGD_RET_UINT32: + fprintf(of, "%u\n", ret->value.ui32); + break; + case ULOGD_RET_IPADDR: + fprintf(of, "%u.%u.%u.%u\n", + HIPQUAD(ret->value.ui32)); + break; + case ULOGD_RET_NONE: + fprintf(of, ""); + break; + } + } + return 0; +} + +static config_entry_t outf_ce = { + .key = "file", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_NONE, + .u = { .string = ULOGD_OPRINT_DEFAULT } +}; + +static void sighup_handler_print(int signal) +{ + + switch (signal) { + case SIGHUP: + ulogd_log(ULOGD_NOTICE, "PKTLOG: reopening logfile\n"); + fclose(of); + of = fopen(outf_ce.u.string, "a"); + if (!of) { + ulogd_log(ULOGD_FATAL, "can't open PKTLOG: %s\n", + strerror(errno)); + exit(2); + } + break; + default: + break; + } +} + +static int oprint_init(void) +{ +#ifdef DEBUG + of = stdout; +#else + config_parse_file("OPRINT", &outf_ce); + + of = fopen(outf_ce.u.string, "a"); + if (!of) { + ulogd_log(ULOGD_FATAL, "can't open PKTLOG: %s\n", + strerror(errno)); + exit(2); + } +#endif + return 0; +} + +static void oprint_fini(void) +{ + if (of != stdout) + fclose(of); + + return; +} + +static ulog_output_t oprint_op = { + .name = "oprint", + .output = &_output_print, + .signal = &sighup_handler_print, + .init = &oprint_init, + .fini = &oprint_fini, +}; + +void _init(void) +{ + register_output(&oprint_op); +} diff --git a/extensions/ulogd_PWSNIFF.c b/extensions/ulogd_PWSNIFF.c new file mode 100644 index 0000000..2ad90c0 --- /dev/null +++ b/extensions/ulogd_PWSNIFF.c @@ -0,0 +1,167 @@ +/* ulogd_PWSNIFF.c, Version $Revision: 5372 $ + * + * ulogd logging interpreter for POP3 / FTP like plaintext passwords. + * + * (C) 2000-2003 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: ulogd_PWSNIFF.c 5372 2005-05-04 01:22:56Z laforge $ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "chtons.h" +#include + +#ifdef DEBUG_PWSNIFF +#define DEBUGP(x) ulogd_log(ULOGD_DEBUG, x) +#else +#define DEBUGP(format, args...) +#endif + + +#define PORT_POP3 110 +#define PORT_FTP 21 + +static u_int16_t pwsniff_ports[] = { + __constant_htons(PORT_POP3), + __constant_htons(PORT_FTP), + /* feel free to include any other ports here, provided that their + * user/password syntax is the same */ +}; + +#define PWSNIFF_MAX_PORTS 2 + +static char *_get_next_blank(char* begp, char *endp) +{ + char *ptr; + + for (ptr = begp; ptr < endp; ptr++) { + if (*ptr == ' ' || *ptr == '\n' || *ptr == '\r') { + return ptr-1; + } + } + return NULL; +} + +static ulog_iret_t *_interp_pwsniff(ulog_interpreter_t *ip, ulog_packet_msg_t *pkt) +{ + struct iphdr *iph = (struct iphdr *) pkt->payload; + void *protoh = (u_int32_t *)iph + iph->ihl; + struct tcphdr *tcph = protoh; + u_int32_t tcplen = ntohs(iph->tot_len) - iph->ihl * 4; + unsigned char *ptr, *begp, *pw_begp, *endp, *pw_endp; + ulog_iret_t *ret = ip->result; + int len, pw_len, i, cont = 0; + + len = pw_len = 0; + begp = pw_begp = NULL; + + if (iph->protocol != IPPROTO_TCP) + return NULL; + + for (i = 0; i < PWSNIFF_MAX_PORTS; i++) + { + if (tcph->dest == pwsniff_ports[i]) { + cont = 1; + break; + } + } + if (!cont) + return NULL; + + DEBUGP("----> pwsniff detected, tcplen=%d, struct=%d, iphtotlen=%d, ihl=%d\n", tcplen, sizeof(struct tcphdr), ntohs(iph->tot_len), iph->ihl); + + for (ptr = (unsigned char *) tcph + sizeof(struct tcphdr); + ptr < (unsigned char *) tcph + tcplen; ptr++) + { + if (!strncasecmp((char *)ptr, "USER ", 5)) { + begp = ptr+5; + endp = (unsigned char *)_get_next_blank((char *)begp, (char *)tcph + tcplen); + if (endp) + len = endp - begp + 1; + } + if (!strncasecmp((char *)ptr, "PASS ", 5)) { + pw_begp = ptr+5; + pw_endp = (unsigned char *)_get_next_blank((char *)pw_begp, + (char *)tcph + tcplen); + if (pw_endp) + pw_len = pw_endp - pw_begp + 1; + } + } + + if (len) { + ret[0].value.ptr = (char *) malloc(len+1); + ret[0].flags |= ULOGD_RETF_VALID; + if (!ret[0].value.ptr) { + ulogd_log(ULOGD_ERROR, "OOM (size=%u)\n", len); + return NULL; + } + strncpy(ret[0].value.ptr, (char *)begp, len); + *((char *)ret[0].value.ptr + len + 1) = '\0'; + } + if (pw_len) { + ret[1].value.ptr = (char *) malloc(pw_len+1); + ret[1].flags |= ULOGD_RETF_VALID; + if (!ret[1].value.ptr){ + ulogd_log(ULOGD_ERROR, "OOM (size=%u)\n", pw_len); + return NULL; + } + strncpy(ret[1].value.ptr, (char *)pw_begp, pw_len); + *((char *)ret[1].value.ptr + pw_len + 1) = '\0'; + + } + return ret; +} + +static ulog_iret_t pwsniff_rets[] = { + { .type = ULOGD_RET_STRING, + .flags = ULOGD_RETF_FREE, + .key = "pwsniff.user", + }, + { .type = ULOGD_RET_STRING, + .flags = ULOGD_RETF_FREE, + .key = "pwsniff.pass", + }, +}; + +static ulog_interpreter_t base_ip[] = { + { .name = "pwsniff", + .interp = &_interp_pwsniff, + .key_num = 2, + .result = pwsniff_rets }, + { NULL, "", 0, NULL, 0, NULL }, +}; + +static void _base_reg_ip(void) +{ + ulog_interpreter_t *ip = base_ip; + ulog_interpreter_t *p; + + for (p = ip; p->interp; p++) + register_interpreter(p); +} + + +void _init(void) +{ + _base_reg_ip(); +} diff --git a/extensions/ulogd_SYSLOG.c b/extensions/ulogd_SYSLOG.c new file mode 100644 index 0000000..5b6aa36 --- /dev/null +++ b/extensions/ulogd_SYSLOG.c @@ -0,0 +1,149 @@ +/* ulogd_SYSLOG.c, Version $Revision: 6433 $ + * + * ulogd output target for real syslog() logging + * + * This target produces a syslog entries identical to the LOG target. + * + * (C) 2003 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: ulogd_SYSLOG.c 6433 2006-01-25 11:22:03Z /C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org $ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "printpkt.h" + +#ifndef SYSLOG_FACILITY_DEFAULT +#define SYSLOG_FACILITY_DEFAULT "LOG_KERN" +#endif + +#ifndef SYSLOG_LEVEL_DEFAULT +#define SYSLOG_LEVEL_DEFAULT "LOG_NOTICE" +#endif + +static config_entry_t facility_ce = { + .key = "facility", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_NONE, + .u = { .string = SYSLOG_FACILITY_DEFAULT } +}; + +static config_entry_t level_ce = { + .next = &facility_ce, + .key = "level", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_NONE, + .u = { .string = SYSLOG_LEVEL_DEFAULT } +}; + +static int syslog_level, syslog_facility; + +static int _output_syslog(ulog_iret_t *res) +{ + static char buf[4096]; + + printpkt_print(res, buf, 0); + syslog(syslog_level|syslog_facility, buf); + + return 0; +} + +static int syslog_init(void) +{ + /* FIXME: error handling */ + config_parse_file("SYSLOG", &level_ce); + + if (!strcmp(facility_ce.u.string, "LOG_DAEMON")) + syslog_facility = LOG_DAEMON; + else if (!strcmp(facility_ce.u.string, "LOG_KERN")) + syslog_facility = LOG_KERN; + else if (!strcmp(facility_ce.u.string, "LOG_LOCAL0")) + syslog_facility = LOG_LOCAL0; + else if (!strcmp(facility_ce.u.string, "LOG_LOCAL1")) + syslog_facility = LOG_LOCAL1; + else if (!strcmp(facility_ce.u.string, "LOG_LOCAL2")) + syslog_facility = LOG_LOCAL2; + else if (!strcmp(facility_ce.u.string, "LOG_LOCAL3")) + syslog_facility = LOG_LOCAL3; + else if (!strcmp(facility_ce.u.string, "LOG_LOCAL4")) + syslog_facility = LOG_LOCAL4; + else if (!strcmp(facility_ce.u.string, "LOG_LOCAL5")) + syslog_facility = LOG_LOCAL5; + else if (!strcmp(facility_ce.u.string, "LOG_LOCAL6")) + syslog_facility = LOG_LOCAL6; + else if (!strcmp(facility_ce.u.string, "LOG_LOCAL7")) + syslog_facility = LOG_LOCAL7; + else if (!strcmp(facility_ce.u.string, "LOG_USER")) + syslog_facility = LOG_USER; + else { + ulogd_log(ULOGD_FATAL, "unknown facility '%s'\n", + facility_ce.u.string); + exit(2); + } + + if (!strcmp(level_ce.u.string, "LOG_EMERG")) + syslog_level = LOG_EMERG; + else if (!strcmp(level_ce.u.string, "LOG_ALERT")) + syslog_level = LOG_ALERT; + else if (!strcmp(level_ce.u.string, "LOG_CRIT")) + syslog_level = LOG_CRIT; + else if (!strcmp(level_ce.u.string, "LOG_ERR")) + syslog_level = LOG_ERR; + else if (!strcmp(level_ce.u.string, "LOG_WARNING")) + syslog_level = LOG_WARNING; + else if (!strcmp(level_ce.u.string, "LOG_NOTICE")) + syslog_level = LOG_NOTICE; + else if (!strcmp(level_ce.u.string, "LOG_INFO")) + syslog_level = LOG_INFO; + else if (!strcmp(level_ce.u.string, "LOG_DEBUG")) + syslog_level = LOG_DEBUG; + else { + ulogd_log(ULOGD_FATAL, "unknown level '%s'\n", + level_ce.u.string); + exit(2); + } + + openlog("ulogd", LOG_NDELAY|LOG_PID, syslog_facility); + + return 0; +} + +static void syslog_fini(void) +{ + closelog(); +} + +static ulog_output_t syslog_op = { + .name = "syslog", + .init = &syslog_init, + .fini = &syslog_fini, + .output = &_output_syslog, +}; + + +void _init(void) +{ + if (printpkt_init()) + ulogd_log(ULOGD_ERROR, "can't resolve all keyhash id's\n"); + + register_output(&syslog_op); +} diff --git a/include/linux/jhash.h b/include/linux/jhash.h new file mode 100644 index 0000000..83f6af2 --- /dev/null +++ b/include/linux/jhash.h @@ -0,0 +1,143 @@ +#ifndef _LINUX_JHASH_H +#define _LINUX_JHASH_H + +/* jhash.h: Jenkins hash support. + * + * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net) + * + * http://burtleburtle.net/bob/hash/ + * + * These are the credits from Bob's sources: + * + * lookup2.c, by Bob Jenkins, December 1996, Public Domain. + * hash(), hash2(), hash3, and mix() are externally useful functions. + * Routines to test the hash are included if SELF_TEST is defined. + * You can use this free for any purpose. It has no warranty. + * + * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * + * I've modified Bob's hash to be useful in the Linux kernel, and + * any bugs present are surely my fault. -DaveM + */ + +/* NOTE: Arguments are modified. */ +#define __jhash_mix(a, b, c) \ +{ \ + a -= b; a -= c; a ^= (c>>13); \ + b -= c; b -= a; b ^= (a<<8); \ + c -= a; c -= b; c ^= (b>>13); \ + a -= b; a -= c; a ^= (c>>12); \ + b -= c; b -= a; b ^= (a<<16); \ + c -= a; c -= b; c ^= (b>>5); \ + a -= b; a -= c; a ^= (c>>3); \ + b -= c; b -= a; b ^= (a<<10); \ + c -= a; c -= b; c ^= (b>>15); \ +} + +/* The golden ration: an arbitrary value */ +#define JHASH_GOLDEN_RATIO 0x9e3779b9 + +/* The most generic version, hashes an arbitrary sequence + * of bytes. No alignment or length assumptions are made about + * the input key. + */ +static inline u32 jhash(void *key, u32 length, u32 initval) +{ + u32 a, b, c, len; + u8 *k = key; + + len = length; + a = b = JHASH_GOLDEN_RATIO; + c = initval; + + while (len >= 12) { + a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24)); + b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24)); + c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24)); + + __jhash_mix(a,b,c); + + k += 12; + len -= 12; + } + + c += length; + switch (len) { + case 11: c += ((u32)k[10]<<24); + case 10: c += ((u32)k[9]<<16); + case 9 : c += ((u32)k[8]<<8); + case 8 : b += ((u32)k[7]<<24); + case 7 : b += ((u32)k[6]<<16); + case 6 : b += ((u32)k[5]<<8); + case 5 : b += k[4]; + case 4 : a += ((u32)k[3]<<24); + case 3 : a += ((u32)k[2]<<16); + case 2 : a += ((u32)k[1]<<8); + case 1 : a += k[0]; + }; + + __jhash_mix(a,b,c); + + return c; +} + +/* A special optimized version that handles 1 or more of u32s. + * The length parameter here is the number of u32s in the key. + */ +static inline u32 jhash2(u32 *k, u32 length, u32 initval) +{ + u32 a, b, c, len; + + a = b = JHASH_GOLDEN_RATIO; + c = initval; + len = length; + + while (len >= 3) { + a += k[0]; + b += k[1]; + c += k[2]; + __jhash_mix(a, b, c); + k += 3; len -= 3; + } + + c += length * 4; + + switch (len) { + case 2 : b += k[1]; + case 1 : a += k[0]; + }; + + __jhash_mix(a,b,c); + + return c; +} + + +/* A special ultra-optimized versions that knows they are hashing exactly + * 3, 2 or 1 word(s). + * + * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally + * done at the end is not done here. + */ +static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval) +{ + a += JHASH_GOLDEN_RATIO; + b += JHASH_GOLDEN_RATIO; + c += initval; + + __jhash_mix(a, b, c); + + return c; +} + +static inline u32 jhash_2words(u32 a, u32 b, u32 initval) +{ + return jhash_3words(a, b, 0, initval); +} + +static inline u32 jhash_1word(u32 a, u32 initval) +{ + return jhash_3words(a, 0, 0, initval); +} + +#endif /* _LINUX_JHASH_H */ diff --git a/include/ulogd/conffile.h b/include/ulogd/conffile.h new file mode 100644 index 0000000..e2921e1 --- /dev/null +++ b/include/ulogd/conffile.h @@ -0,0 +1,66 @@ +/* config file parser functions + * + * (C) 2000 by Harald Welte + * + * $Id: conffile.h 4946 2003-09-28 15:19:25Z laforge $ + * + * This code is distributed under the terms of GNU GPL */ + +#ifndef _CONFFILE_H +#define _CONFFILE_H + +#include + +/* errors returned by config functions */ +enum { + ERRNONE = 0, + ERROPEN, /* unable to open config file */ + ERROOM, /* out of memory */ + ERRMULT, /* non-multiple option occured more than once */ + ERRMAND, /* mandatory option not found */ + ERRUNKN, /* unknown config key */ + ERRSECTION, /* section not found */ +}; + +/* maximum line lenght of config file entries */ +#define LINE_LEN 255 + +/* maximum lenght of config key name */ +#define CONFIG_KEY_LEN 30 + +/* maximum lenght of string config value */ +#define CONFIG_VAL_STRING_LEN 225 + +/* valid config types */ +#define CONFIG_TYPE_INT 0x0001 +#define CONFIG_TYPE_STRING 0x0002 +#define CONFIG_TYPE_CALLBACK 0x0003 + +/* valid config options */ +#define CONFIG_OPT_NONE 0x0000 +#define CONFIG_OPT_MANDATORY 0x0001 +#define CONFIG_OPT_MULTI 0x0002 + +typedef struct config_entry { + struct config_entry *next; /* the next one in linked list */ + char key[CONFIG_KEY_LEN]; /* name of config directive */ + u_int8_t type; /* type; see above */ + u_int8_t options; /* options; see above */ + u_int8_t hit; /* found? */ + union { + char string[CONFIG_VAL_STRING_LEN]; + int value; + int (*parser)(char *argstr); + } u; +} config_entry_t; + +/* if an error occurs, config_errce is set to the erroneous ce */ +extern config_entry_t *config_errce; + +/* tell us the name of the config file */ +int config_register_file(const char *file); + +/* parse the config file */ +int config_parse_file(const char *section, config_entry_t *keys); + +#endif /* ifndef _CONFFILE_H */ diff --git a/include/ulogd/gre.h b/include/ulogd/gre.h new file mode 100644 index 0000000..50cc7d5 --- /dev/null +++ b/include/ulogd/gre.h @@ -0,0 +1,34 @@ +#ifndef _ULOGD_GRE_H_ +#define _ULOGD_GRE_H_ + +#define GRE_FLAG_CKSUM htons(0x8000) /* Checksum Present */ +#define GRE_FLAG_ROUTE htons(0x4000) /* Routing Present */ +#define GRE_FLAG_KEY htons(0x2000) /* Key Present */ +#define GRE_FLAG_SEQ htons(0x1000) /* Sequence Present */ +#define GRE_FLAG_SSR htons(0x0800) /* Strict Source Route */ +#define GRE_FLAG_RECUR htons(0x0700) /* Recursion Control */ +#define GRE_FLAG_ACK htons(0x0080) /* Acknowledgement Present (PPTP only) */ +#define GRE_FLAG_FLAGS htons(0x0078) /* Additional Flags */ +#define GRE_FLAG_VER htons(0x0007) /* Version Number */ +#define GRE_VER_GRE htons(0x0000) /* GRE version 0 (RFC1701 GRE) */ +#define GRE_VER_PPTP htons(0x0001) /* Enhanced GRE (RFC2637 PPTP) */ + +struct grehdr { + u_int16_t flags_ver; /* See above */ + u_int16_t protocol; /* Ethernet protocol type */ + u_int16_t cksum; /* present if (flags_ver & GRE_FLAG_CKSUM) */ + u_int16_t reserved1; /* present if (flags_ver & GRE_FLAG_CKSUM) */ + u_int32_t key; /* present if (flags_ver & GRE_FLAG_KEY) */ + u_int32_t seq; /* present if (flags_ver & GRE_FLAG_SEQ) */ +}; + +struct pptphdr { + u_int16_t flags_ver; /* See above */ + u_int16_t protocol; /* Ethernet protocol type */ + u_int16_t payload_len; /* following payload length (not including this header) */ + u_int16_t call_id; /* peer call ID */ + u_int32_t seq; /* present if (flags_ver & GRE_FLAG_SEQ) */ + u_int32_t ack; /* present if (flags_ver & GRE_FLAG_ACK) */ +}; + +#endif /* _ULOGD_GRE_H_ */ diff --git a/include/ulogd/ulogd.h b/include/ulogd/ulogd.h new file mode 100644 index 0000000..e1e4e6d --- /dev/null +++ b/include/ulogd/ulogd.h @@ -0,0 +1,162 @@ +#ifndef _ULOGD_H +#define _ULOGD_H +/* ulogd, Version $Revision: 5369 $ + * + * userspace logging daemon for netfilter ULOG target + * of the linux 2.4 netfilter subsystem. + * + * (C) 2000 by Harald Welte + * + * this code is released under the terms of GNU GPL + * + * $Id: ulogd.h 5369 2005-05-04 01:16:57Z laforge $ + */ + +#include +#include +#include /* need this because of extension-sighandler */ + +/* All types with MSB = 1 make use of value.ptr + * other types use one of the union's member */ + +/* types without length */ +#define ULOGD_RET_NONE 0x0000 + +#define ULOGD_RET_INT8 0x0001 +#define ULOGD_RET_INT16 0x0002 +#define ULOGD_RET_INT32 0x0003 +#define ULOGD_RET_INT64 0x0004 + +#define ULOGD_RET_UINT8 0x0011 +#define ULOGD_RET_UINT16 0x0012 +#define ULOGD_RET_UINT32 0x0013 +#define ULOGD_RET_UINT64 0x0014 + +#define ULOGD_RET_BOOL 0x0050 + +#define ULOGD_RET_IPADDR 0x0100 + +/* types with length field */ +#define ULOGD_RET_STRING 0x8020 +#define ULOGD_RET_RAW 0x8030 + + +/* FLAGS */ +#define ULOGD_RETF_NONE 0x0000 +#define ULOGD_RETF_VALID 0x0001 /* contains a valid result */ +#define ULOGD_RETF_FREE 0x0002 /* ptr needs to be free()d */ + + +/* maximum length of ulogd key */ +#define ULOGD_MAX_KEYLEN 32 + +#define ULOGD_DEBUG 1 /* debugging information */ +#define ULOGD_INFO 3 +#define ULOGD_NOTICE 5 /* abnormal/unexpected condition */ +#define ULOGD_ERROR 7 /* error condition, requires user action */ +#define ULOGD_FATAL 8 /* fatal, program aborted */ + +typedef struct ulog_iret { + /* next interpreter return (key) in the global list */ + struct ulog_iret *next; + /* next interpreter in linked list for current result */ + struct ulog_iret *cur_next; + /* length of the returned value (only for lengthed types */ + u_int32_t len; + /* type of the returned value (ULOGD_IRET_...) */ + u_int16_t type; + /* flags (i.e. free, ...) */ + u_int16_t flags; + /* name of this key */ + char key[ULOGD_MAX_KEYLEN]; + /* and finally the returned value */ + union { + u_int8_t b; + u_int8_t ui8; + u_int16_t ui16; + u_int32_t ui32; + u_int64_t ui64; + int8_t i8; + int16_t i16; + int32_t i32; + int64_t i64; + void *ptr; + } value; +} ulog_iret_t; + +typedef struct ulog_interpreter { + /* next interpreter in old-style linked list */ + struct ulog_interpreter *next; + /* name of this interpreter (predefined by plugin) */ + char name[ULOGD_MAX_KEYLEN]; + /* ID for this interpreter (dynamically assigned) */ + unsigned int id; + /* function to call for each packet */ + ulog_iret_t* (*interp)(struct ulog_interpreter *ip, + ulog_packet_msg_t *pkt); + /* number of keys this interpreter has */ + unsigned int key_num; + /* keys of this particular interpreter */ + ulog_iret_t *result; +} ulog_interpreter_t; + +typedef struct ulog_output { + /* next output in the linked list */ + struct ulog_output *next; + /* name of this ouput plugin */ + char name[ULOGD_MAX_KEYLEN]; + /* callback for initialization */ + int (*init)(void); + /* callback for de-initialization */ + void (*fini)(void); + /* callback function */ + int (*output)(ulog_iret_t *ret); + /* callback function for signals (SIGHUP, ..) */ + void (*signal)(int signal); +} ulog_output_t; + +/* entries of the key hash */ +struct ulogd_keyh_entry { + ulog_interpreter_t *interp; /* interpreter for this key */ + unsigned int offset; /* offset within interpreter */ + const char *name; /* name of this particular key */ +}; + +/*********************************************************************** + * PUBLIC INTERFACE + ***********************************************************************/ + +/* register a new interpreter plugin */ +void register_interpreter(ulog_interpreter_t *me); + +/* register a new output target */ +void register_output(ulog_output_t *me); + +/* allocate a new ulog_iret_t */ +ulog_iret_t *alloc_ret(const u_int16_t type, const char*); + +/* write a message to the daemons' logfile */ +void __ulogd_log(int level, char *file, int line, const char *message, ...); +/* macro for logging including filename and line number */ +#define ulogd_log(level, format, args...) \ + __ulogd_log(level, __FILE__, __LINE__, format, ## args) +/* backwards compatibility */ +#define ulogd_error(format, args...) ulogd_log(ULOGD_ERROR, format, ## args) + +/* get an interpreter hash id by name */ +unsigned int interh_getid(const char *name); + +/* get a key id if you have the name */ +unsigned int keyh_getid(const char *name); + +/* get a result for a given key id */ +ulog_iret_t *keyh_getres(unsigned int id); + +/* the key hash itself */ +extern struct ulogd_keyh_entry *ulogd_keyh; + +#define IS_VALID(x) (x.flags & ULOGD_RETF_VALID) + +#define SET_VALID(x) (x.flags |= ULOGD_RETF_VALID) + +#endif /* _ULOGD_H */ diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..e9de238 --- /dev/null +++ b/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/libipulog/Makefile.in b/libipulog/Makefile.in new file mode 100644 index 0000000..52a3394 --- /dev/null +++ b/libipulog/Makefile.in @@ -0,0 +1,23 @@ +# + +include @top_srcdir@/Rules.make +CFLAGS+=-Iinclude -I/usr/src/linux/include + +libipulog.a: libipulog.o + $(LD) -i $< -o $@ + +distrib: + +ulog_test: ulog_test.c libipulog.a + $(CC) $(CFLAGS) ulog_test.c libipulog.a -o ulog_test + +libipulog.o: libipulog.c + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + $(RM) ulog_test libipulog.o libipulog.a + +distclean: clean + $(RM) Makefile + +install: libipulog.a diff --git a/libipulog/include/libipulog/libipulog.h b/libipulog/include/libipulog/libipulog.h new file mode 100644 index 0000000..346be69 --- /dev/null +++ b/libipulog/include/libipulog/libipulog.h @@ -0,0 +1,58 @@ +#ifndef _LIBIPULOG_H +#define _LIBIPULOG_H + +/* $Id: libipulog.h 4915 2003-05-04 10:00:10Z laforge $ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* FIXME: glibc sucks */ +#ifndef MSG_TRUNC +#define MSG_TRUNC 0x20 +#endif + +struct ipulog_handle; +extern int ipulog_errno; + +u_int32_t ipulog_group2gmask(u_int32_t group); + +struct ipulog_handle *ipulog_create_handle(u_int32_t gmask, u_int32_t rmem); + +void ipulog_destroy_handle(struct ipulog_handle *h); + +ssize_t ipulog_read(struct ipulog_handle *h, + unsigned char *buf, size_t len, int timeout); + +ulog_packet_msg_t *ipulog_get_packet(struct ipulog_handle *h, + const unsigned char *buf, + size_t len); + +char *ipulog_strerror(int errcode); + +void ipulog_perror(const char *s); + +enum +{ + IPULOG_ERR_NONE = 0, + IPULOG_ERR_IMPL, + IPULOG_ERR_HANDLE, + IPULOG_ERR_SOCKET, + IPULOG_ERR_BIND, + IPULOG_ERR_RECVBUF, + IPULOG_ERR_RECV, + IPULOG_ERR_NLEOF, + IPULOG_ERR_TRUNC, + IPULOG_ERR_INVGR, + IPULOG_ERR_INVNL, +}; +#define IPULOG_MAXERR IPULOG_ERR_INVNL + +#endif /* _LIBULOG_H */ diff --git a/libipulog/libipulog.c b/libipulog/libipulog.c new file mode 100644 index 0000000..6adf857 --- /dev/null +++ b/libipulog/libipulog.c @@ -0,0 +1,276 @@ +/* + * libipulog.c, $Revision: 5371 $ + * + * netfilter ULOG userspace library. + * + * (C) 2000-2001 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This library is still under development, so be aware of sudden interface + * changes + * + * $Id: libipulog.c 5371 2005-05-04 01:22:18Z laforge $ + */ + +#include +#include +#include +#include +#include +#include +#if HAVE_LIBPROPER +#include +#endif + +struct ipulog_handle +{ + int fd; + u_int8_t blocking; + struct sockaddr_nl local; + struct sockaddr_nl peer; + struct nlmsghdr* last_nlhdr; +}; + +/* internal */ + + +int ipulog_errno = IPULOG_ERR_NONE; + +struct ipulog_errmap_t +{ + int errcode; + char *message; +} ipulog_errmap[] = +{ + { IPULOG_ERR_NONE, "No error" }, + { IPULOG_ERR_IMPL, "Not implemented yet" }, + { IPULOG_ERR_HANDLE, "Unable to create netlink handle" }, + { IPULOG_ERR_SOCKET, "Unable to create netlink socket" }, + { IPULOG_ERR_BIND, "Unable to bind netlink socket" }, + { IPULOG_ERR_RECVBUF, "Receive buffer size invalid" }, + { IPULOG_ERR_RECV, "Error during netlink receive" }, + { IPULOG_ERR_NLEOF, "Received EOF on netlink socket" }, + { IPULOG_ERR_TRUNC, "Receive message truncated" }, + { IPULOG_ERR_INVGR, "Invalid group specified" }, + { IPULOG_ERR_INVNL, "Invalid netlink message" }, +}; + +static ssize_t +ipulog_netlink_recvfrom(const struct ipulog_handle *h, + unsigned char *buf, size_t len) +{ + socklen_t addrlen; + int status; + struct nlmsghdr *nlh; + + if (len < sizeof(struct nlmsgerr)) { + ipulog_errno = IPULOG_ERR_RECVBUF; + return -1; + } + addrlen = sizeof(h->peer); + status = recvfrom(h->fd, buf, len, 0, (struct sockaddr *)&h->peer, + &addrlen); + if (status < 0) { + ipulog_errno = IPULOG_ERR_RECV; + return status; + } + if (addrlen != sizeof (h->peer)) { + ipulog_errno = IPULOG_ERR_RECV; + return -1; + } + if (h->peer.nl_pid != 0) { + ipulog_errno = IPULOG_ERR_RECV; + return -1; + } + if (status == 0) { + ipulog_errno = IPULOG_ERR_NLEOF; + return -1; + } + nlh = (struct nlmsghdr *)buf; + if (nlh->nlmsg_flags & MSG_TRUNC || status > len) { + ipulog_errno = IPULOG_ERR_TRUNC; + return -1; + } + return status; +} + +/* public */ + +char *ipulog_strerror(int errcode) +{ + if (errcode < 0 || errcode > IPULOG_MAXERR) + errcode = IPULOG_ERR_IMPL; + return ipulog_errmap[errcode].message; +} + +/* convert a netlink group (1-32) to a group_mask suitable for create_handle */ +u_int32_t ipulog_group2gmask(u_int32_t group) +{ + if (group < 1 || group > 32) + { + ipulog_errno = IPULOG_ERR_INVGR; + return 0; + } + return (1 << (group - 1)); +} + +/* create a ipulog handle for the reception of packets sent to gmask */ +struct ipulog_handle *ipulog_create_handle(u_int32_t gmask, + u_int32_t rcvbufsize) +{ + struct ipulog_handle *h; + int status; + + h = (struct ipulog_handle *) malloc(sizeof(struct ipulog_handle)); + if (h == NULL) + { + ipulog_errno = IPULOG_ERR_HANDLE; + return NULL; + } + memset(h, 0, sizeof(struct ipulog_handle)); +#if HAVE_LIBPROPER + /* Create and bind privileged netlink socket through Proper */ + memset(&h->local, 0, sizeof(struct sockaddr_nl)); + h->local.nl_family = AF_NETLINK; + h->local.nl_pid = getpid(); + h->local.nl_groups = gmask; + h->fd = prop_create_socket(PF_NETLINK, SOCK_RAW, NETLINK_NFLOG, + (struct sockaddr *)&h->local, sizeof(h->local)); + if (h->fd < 0) + { + ipulog_errno = IPULOG_ERR_SOCKET; + close(h->fd); + free(h); + return NULL; + } +#else + h->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_NFLOG); + if (h->fd == -1) + { + ipulog_errno = IPULOG_ERR_SOCKET; + close(h->fd); + free(h); + return NULL; + } + memset(&h->local, 0, sizeof(struct sockaddr_nl)); + h->local.nl_family = AF_NETLINK; + h->local.nl_pid = getpid(); + h->local.nl_groups = gmask; + status = bind(h->fd, (struct sockaddr *)&h->local, sizeof(h->local)); + if (status == -1) + { + ipulog_errno = IPULOG_ERR_BIND; + close(h->fd); + free(h); + return NULL; + } +#endif + memset(&h->peer, 0, sizeof(struct sockaddr_nl)); + h->peer.nl_family = AF_NETLINK; + h->peer.nl_pid = 0; + h->peer.nl_groups = gmask; + + status = setsockopt(h->fd, SOL_SOCKET, SO_RCVBUF, &rcvbufsize, + sizeof(rcvbufsize)); + if (status == -1) + { + ipulog_errno = IPULOG_ERR_RECVBUF; + close(h->fd); + free(h); + return NULL; + } + + return h; +} + +/* destroy a ipulog handle */ +void ipulog_destroy_handle(struct ipulog_handle *h) +{ + close(h->fd); + free(h); +} + +#if 0 +int ipulog_set_mode() +{ +} +#endif + +/* do a BLOCKING read on an ipulog handle */ +ssize_t ipulog_read(struct ipulog_handle *h, unsigned char *buf, + size_t len, int timeout) +{ + return ipulog_netlink_recvfrom(h, buf, len); +} + +/* get a pointer to the actual start of the ipulog packet, + use this to strip netlink header */ +ulog_packet_msg_t *ipulog_get_packet(struct ipulog_handle *h, + const unsigned char *buf, + size_t len) +{ + struct nlmsghdr *nlh; + size_t remain_len; + + /* if last header in handle not inside this buffer, + * drop reference to last header */ + if ((unsigned char *)h->last_nlhdr > (buf + len) || + (unsigned char *)h->last_nlhdr < buf) { + h->last_nlhdr = NULL; + } + + if (!h->last_nlhdr) { + /* fist message in buffer */ + nlh = (struct nlmsghdr *) buf; + if (!NLMSG_OK(nlh, len)) { + /* ERROR */ + ipulog_errno = IPULOG_ERR_INVNL; + return NULL; + } + } else { + /* we are in n-th part of multilink message */ + if (h->last_nlhdr->nlmsg_type == NLMSG_DONE || + !(h->last_nlhdr->nlmsg_flags & NLM_F_MULTI)) { + /* if last part in multilink message, + * or no multipart message at all: return */ + h->last_nlhdr = NULL; + return NULL; + } + + /* calculate remaining lenght from lasthdr to end of buffer */ + remain_len = (len - + ((unsigned char *)h->last_nlhdr - buf)); + nlh = NLMSG_NEXT(h->last_nlhdr, remain_len); + } + + h->last_nlhdr = nlh; + + return NLMSG_DATA(nlh); +} + +/* print a human readable description of the last error to stderr */ +void ipulog_perror(const char *s) +{ + if (s) + fputs(s, stderr); + else + fputs("ERROR", stderr); + if (ipulog_errno) + fprintf(stderr, ": %s", ipulog_strerror(ipulog_errno)); + if (errno) + fprintf(stderr, ": %s", strerror(errno)); + fputc('\n', stderr); +} + diff --git a/libipulog/ulog_test.c b/libipulog/ulog_test.c new file mode 100644 index 0000000..80dc4b2 --- /dev/null +++ b/libipulog/ulog_test.c @@ -0,0 +1,84 @@ +/* ulog_test, $Revision: 5293 $ + * + * small testing program for libipulog, part of the netfilter ULOG target + * for the linux 2.4 netfilter subsystem. + * + * (C) 2000-2005 by Harald Welte + * + * this code is released under the terms of GNU GPL + * + * $Id: ulog_test.c 5293 2005-03-11 11:47:53Z laforge $ + */ + +#include +#include +#include + +#define MYBUFSIZ 2048 + +/* prints some logging about a single packet */ +void handle_packet(ulog_packet_msg_t *pkt) +{ + unsigned char *p; + int i; + + printf("Hook=%u Mark=%lu len=%d ", + pkt->hook, pkt->mark, pkt->data_len); + if (strlen(pkt->prefix)) + printf("Prefix=%s ", pkt->prefix); + + if (pkt->mac_len) + { + printf("mac="); + p = pkt->mac; + for (i = 0; i < pkt->mac_len; i++, p++) + printf("%02x%c", *p, i==pkt->mac_len-1 ? ' ':':'); + } + printf("\n"); + +} + +int main(int argc, char *argv[]) +{ + struct ipulog_handle *h; + unsigned char* buf; + int len; + ulog_packet_msg_t *upkt; + int i; + + if (argc != 4) { + fprintf(stderr, "Usage: %s count group timeout\n", argv[0]); + exit(1); + } + + /* allocate a receive buffer */ + buf = (unsigned char *) malloc(MYBUFSIZ); + + /* create ipulog handle */ + h = ipulog_create_handle(ipulog_group2gmask(atoi(argv[2])),150000); + if (!h) + { + /* if some error occurrs, print it to stderr */ + ipulog_perror(NULL); + exit(1); + } + + alarm(atoi(argv[3])); + + /* loop receiving packets and handling them over to handle_packet */ + for (i = 0; i < atoi(argv[1]); i++) { + len = ipulog_read(h, buf, MYBUFSIZ, 1); + if (len <= 0) { + ipulog_perror("ulog_test: short read"); + exit(1); + } + printf("%d bytes received\n", len); + while (upkt = ipulog_get_packet(h, buf, len)) { + handle_packet(upkt); + } + } + + /* just to give it a cleaner look */ + ipulog_destroy_handle(h); + return 0; +} diff --git a/mysql/Makefile b/mysql/Makefile new file mode 100644 index 0000000..a985a0b --- /dev/null +++ b/mysql/Makefile @@ -0,0 +1,30 @@ +# + +# Normally You should not need to change anything below +# +include ../Rules.make + +CFLAGS+=-I.. -I../libipulog/include -I../include +SH_CFLAGS:=$(CFLAGS) -fPIC + +SHARED_LIBS=ulogd_MYSQL.so + +all: $(SHARED_LIBS) + +distrib: + +$(SHARED_LIBS): %.so: %_sh.o + $(LD) -shared $(MYSQL_LDFLAGS) -o $@ $< -lc + +%_sh.o: %.c + $(CC) $(MYSQL_CFLAGS) $(SH_CFLAGS) -o $@ -c $< + +clean: + $(RM) $(SHARED_LIBS) *.o + +distclean: + $(RM) Makefile + +install: all + $(INSTALL) -m 755 -d $(DESTDIR)$(ULOGD_LIB_PATH) + $(INSTALL) -m 755 *.so $(DESTDIR)$(ULOGD_LIB_PATH) diff --git a/mysql/Makefile.in b/mysql/Makefile.in new file mode 100644 index 0000000..cbab843 --- /dev/null +++ b/mysql/Makefile.in @@ -0,0 +1,30 @@ +# + +# Normally You should not need to change anything below +# +include @top_srcdir@/Rules.make + +CFLAGS+=-I@top_srcdir@ -I@top_srcdir@/libipulog/include -I@top_srcdir@/include +SH_CFLAGS:=$(CFLAGS) -fPIC + +SHARED_LIBS=ulogd_MYSQL.so + +all: $(SHARED_LIBS) + +distrib: + +$(SHARED_LIBS): %.so: %_sh.o + $(LD) -shared $(MYSQL_LDFLAGS) -o $@ $< -lc + +%_sh.o: %.c + $(CC) $(MYSQL_CFLAGS) $(SH_CFLAGS) -o $@ -c $< + +clean: + $(RM) $(SHARED_LIBS) *.o + +distclean: + $(RM) Makefile + +install: all + $(INSTALL) -m 755 -d $(DESTDIR)$(ULOGD_LIB_PATH) + $(INSTALL) -m 755 *.so $(DESTDIR)$(ULOGD_LIB_PATH) diff --git a/mysql/ulogd_MYSQL.c b/mysql/ulogd_MYSQL.c new file mode 100644 index 0000000..b4691de --- /dev/null +++ b/mysql/ulogd_MYSQL.c @@ -0,0 +1,454 @@ +/* ulogd_MYSQL.c, Version $Revision: 5875 $ + * + * ulogd output plugin for logging to a MySQL database + * + * (C) 2000-2001 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: ulogd_MYSQL.c 5875 2005-08-01 06:49:59Z laforge $ + * + * 15 May 2001, Alex Janssen : + * Added a compability option for older MySQL-servers, which + * don't support mysql_real_escape_string + * + * 17 May 2001, Alex Janssen : + * Added the --with-mysql-log-ip-as-string feature. This will log + * IP's as string rather than an unsigned long integer to the database. + * See ulogd/doc/mysql.table.ipaddr-as-string as an example. + * BE WARNED: This has _WAY_ less performance during table searches. + * + * 09 Feb 2005, Sven Schuster : + * Added the "port" parameter to specify ports different from 3306 + * + * 12 May 2005, Jozsef Kadlecsik + * Added reconnecting to lost mysql server. + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG_MYSQL +#define DEBUGP(x, args...) fprintf(stderr, x, ## args) +#else +#define DEBUGP(x, args...) +#endif + +struct _field { + char name[ULOGD_MAX_KEYLEN]; + unsigned int id; + struct _field *next; +}; + +/* The plugin handler */ +static ulog_output_t mysql_plugin; + +/* the database handle we are using */ +static MYSQL *dbh; + +/* a linked list of the fields the table has */ +static struct _field *fields; + +/* buffer for our insert statement */ +static char *stmt; + +/* pointer to the beginning of the "VALUES" part */ +static char *stmt_val; + +/* pointer to current inser position in statement */ +static char *stmt_ins; + +/* Attempt to reconnect if connection is lost */ +time_t reconnect = 0; +#define TIME_ERR ((time_t)-1) /* Be paranoid */ + +/* our configuration directives */ +static config_entry_t db_ce = { + .key = "db", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_MANDATORY, +}; + +static config_entry_t host_ce = { + .next = &db_ce, + .key = "host", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_MANDATORY, +}; + +static config_entry_t user_ce = { + .next = &host_ce, + .key = "user", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_MANDATORY, +}; + +static config_entry_t pass_ce = { + .next = &user_ce, + .key = "pass", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_MANDATORY, +}; + +static config_entry_t table_ce = { + .next = &pass_ce, + .key = "table", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_MANDATORY, +}; + +static config_entry_t port_ce = { + .next = &table_ce, + .key = "port", + .type = CONFIG_TYPE_INT, +}; + +static config_entry_t reconnect_ce = { + .next = &port_ce, + .key = "reconnect", + .type = CONFIG_TYPE_INT, +}; + +static config_entry_t connect_timeout_ce = { + .next = &reconnect_ce, + .key = "connect_timeout", + .type = CONFIG_TYPE_INT, +}; + +static int _mysql_init_db(ulog_iret_t *result); + +/* our main output function, called by ulogd */ +static int mysql_output(ulog_iret_t *result) +{ + struct _field *f; + ulog_iret_t *res; +#ifdef IP_AS_STRING + char *tmpstr; /* need this for --log-ip-as-string */ + struct in_addr addr; +#endif + + stmt_ins = stmt_val; + + for (f = fields; f; f = f->next) { + res = keyh_getres(f->id); + + if (!res) { + ulogd_log(ULOGD_NOTICE, + "no result for %s ?!?\n", f->name); + } + + if (!res || !IS_VALID((*res))) { + /* no result, we have to fake something */ + sprintf(stmt_ins, "NULL,"); + stmt_ins = stmt + strlen(stmt); + continue; + } + + switch (res->type) { + case ULOGD_RET_INT8: + sprintf(stmt_ins, "%d,", res->value.i8); + break; + case ULOGD_RET_INT16: + sprintf(stmt_ins, "%d,", res->value.i16); + break; + case ULOGD_RET_INT32: + sprintf(stmt_ins, "%d,", res->value.i32); + break; + case ULOGD_RET_INT64: + sprintf(stmt_ins, "%lld,", res->value.i64); + break; + case ULOGD_RET_UINT8: + sprintf(stmt_ins, "%u,", res->value.ui8); + break; + case ULOGD_RET_UINT16: + sprintf(stmt_ins, "%u,", res->value.ui16); + break; + case ULOGD_RET_IPADDR: +#ifdef IP_AS_STRING + memset(&addr, 0, sizeof(addr)); + addr.s_addr = ntohl(res->value.ui32); + *stmt_ins++ = '\''; + tmpstr = inet_ntoa(addr); +#ifdef OLD_MYSQL + mysql_escape_string(stmt_ins, tmpstr, + strlen(tmpstr)); +#else + mysql_real_escape_string(dbh, stmt_ins, + tmpstr, + strlen(tmpstr)); +#endif /* OLD_MYSQL */ + stmt_ins = stmt + strlen(stmt); + sprintf(stmt_ins, "',"); + break; +#endif /* IP_AS_STRING */ + /* EVIL: fallthrough when logging IP as + * u_int32_t */ + case ULOGD_RET_UINT32: + sprintf(stmt_ins, "%u,", res->value.ui32); + break; + case ULOGD_RET_UINT64: + sprintf(stmt_ins, "%llu,", res->value.ui64); + break; + case ULOGD_RET_BOOL: + sprintf(stmt_ins, "'%d',", res->value.b); + break; + case ULOGD_RET_STRING: + *stmt_ins++ = '\''; +#ifdef OLD_MYSQL + mysql_escape_string(stmt_ins, res->value.ptr, + strlen(res->value.ptr)); +#else + mysql_real_escape_string(dbh, stmt_ins, + res->value.ptr, strlen(res->value.ptr)); +#endif + stmt_ins = stmt + strlen(stmt); + sprintf(stmt_ins, "',"); + /* sprintf(stmt_ins, "'%s',", res->value.ptr); */ + break; + case ULOGD_RET_RAW: + ulogd_log(ULOGD_NOTICE, + "%s: type RAW not supported by MySQL\n", + res->key); + break; + default: + ulogd_log(ULOGD_NOTICE, + "unknown type %d for %s\n", + res->type, res->key); + break; + } + stmt_ins = stmt + strlen(stmt); + } + *(stmt_ins - 1) = ')'; + DEBUGP("stmt=#%s#\n", stmt); + + /* now we have created our statement, insert it */ + + if (mysql_real_query(dbh, stmt, strlen(stmt))) { + ulogd_log(ULOGD_ERROR, "sql error during insert: %s\n", + mysql_error(dbh)); + return _mysql_init_db(result); + } + + return 0; +} + +/* no connection, plugin disabled */ +static int mysql_output_disabled(ulog_iret_t *result) +{ + return 0; +} + +#define MYSQL_INSERTTEMPL "insert into X (Y) values (Z)" +#define MYSQL_VALSIZE 100 + +/* create the static part of our insert statement */ +static int mysql_createstmt(void) +{ + struct _field *f; + unsigned int size; + char buf[ULOGD_MAX_KEYLEN]; + char *underscore; + + if (stmt) + free(stmt); + + /* caclulate the size for the insert statement */ + size = strlen(MYSQL_INSERTTEMPL) + strlen(table_ce.u.string); + + for (f = fields; f; f = f->next) { + /* we need space for the key and a comma, as well as + * enough space for the values */ + size += strlen(f->name) + 1 + MYSQL_VALSIZE; + } + + ulogd_log(ULOGD_DEBUG, "allocating %u bytes for statement\n", size); + + stmt = (char *) malloc(size); + + if (!stmt) { + ulogd_log(ULOGD_ERROR, "OOM!\n"); + return -1; + } + + sprintf(stmt, "insert into %s (", table_ce.u.string); + stmt_val = stmt + strlen(stmt); + + for (f = fields; f; f = f->next) { + strncpy(buf, f->name, ULOGD_MAX_KEYLEN); + while ((underscore = strchr(buf, '.'))) + *underscore = '_'; + sprintf(stmt_val, "%s,", buf); + stmt_val = stmt + strlen(stmt); + } + *(stmt_val - 1) = ')'; + + sprintf(stmt_val, " values ("); + stmt_val = stmt + strlen(stmt); + + ulogd_log(ULOGD_DEBUG, "stmt='%s'\n", stmt); + + return 0; +} + +/* find out which columns the table has */ +static int mysql_get_columns(const char *table) +{ + MYSQL_RES *result; + MYSQL_FIELD *field; + char buf[ULOGD_MAX_KEYLEN]; + char *underscore; + struct _field *f; + int id; + + if (!dbh) + return -1; + + result = mysql_list_fields(dbh, table, NULL); + if (!result) + return -1; + + /* Cleanup before reconnect */ + while (fields) { + f = fields; + fields = f->next; + free(f); + } + + while ((field = mysql_fetch_field(result))) { + + /* replace all underscores with dots */ + strncpy(buf, field->name, ULOGD_MAX_KEYLEN); + while ((underscore = strchr(buf, '_'))) + *underscore = '.'; + + DEBUGP("field '%s' found: ", buf); + + if (!(id = keyh_getid(buf))) { + DEBUGP(" no keyid!\n"); + continue; + } + + DEBUGP("keyid %u\n", id); + + /* prepend it to the linked list */ + f = (struct _field *) malloc(sizeof *f); + if (!f) { + ulogd_log(ULOGD_ERROR, "OOM!\n"); + return -1; + } + strncpy(f->name, buf, ULOGD_MAX_KEYLEN); + f->id = id; + f->next = fields; + fields = f; + } + + mysql_free_result(result); + return 0; +} + +/* make connection and select database */ +static int mysql_open_db(char *server, int port, char *user, char *pass, + char *db) +{ + dbh = mysql_init(NULL); + if (!dbh) + return -1; + + if (connect_timeout_ce.u.value) + mysql_options(dbh, MYSQL_OPT_CONNECT_TIMEOUT, (const char *) &connect_timeout_ce.u.value); + + if (!mysql_real_connect(dbh, server, user, pass, db, port, NULL, 0)) + return -1; + + return 0; +} + +static int init_reconnect(void) +{ + if (reconnect_ce.u.value) { + reconnect = time(NULL); + if (reconnect != TIME_ERR) { + ulogd_log(ULOGD_ERROR, "no connection to database, " + "attempting to reconnect " + "after %u seconds\n", + reconnect_ce.u.value); + reconnect += reconnect_ce.u.value; + mysql_plugin.output = &_mysql_init_db; + return -1; + } + } + /* Disable plugin permanently */ + mysql_plugin.output = &mysql_output_disabled; + + return 0; +} + +static int _mysql_init_db(ulog_iret_t *result) +{ + if (reconnect && reconnect > time(NULL)) + return 0; + + if (mysql_open_db(host_ce.u.string, port_ce.u.value, user_ce.u.string, + pass_ce.u.string, db_ce.u.string)) { + ulogd_log(ULOGD_ERROR, "can't establish database connection\n"); + return init_reconnect(); + } + + /* read the fieldnames to know which values to insert */ + if (mysql_get_columns(table_ce.u.string)) { + ulogd_log(ULOGD_ERROR, "unable to get mysql columns\n"); + return init_reconnect(); + } + mysql_createstmt(); + + /* enable plugin */ + mysql_plugin.output = &mysql_output; + + reconnect = 0; + + if (result) + return mysql_output(result); + + return 0; +} + +static int _mysql_init(void) +{ + /* have the opts parsed */ + config_parse_file("MYSQL", &connect_timeout_ce); + + return _mysql_init_db(NULL); +} + +static void _mysql_fini(void) +{ + mysql_close(dbh); +} + +static ulog_output_t mysql_plugin = { + .name = "mysql", + .output = &mysql_output, + .init = &_mysql_init, + .fini = &_mysql_fini, +}; + +void _init(void) +{ + register_output(&mysql_plugin); +} diff --git a/netflow/Makefile.in b/netflow/Makefile.in new file mode 100644 index 0000000..48e4e06 --- /dev/null +++ b/netflow/Makefile.in @@ -0,0 +1,34 @@ +# +include @top_srcdir@/Rules.make + +CFLAGS+=-I@top_srcdir@ -I@top_srcdir@/libipulog/include -I@top_srcdir@/include +SH_CFLAGS:=$(CFLAGS) -fPIC + +# Normally You should not need to change anything below +# + +SHARED_LIBS=ulogd_NETFLOW.so + +all: $(SHARED_LIBS) netflow-import + +distrib: + +$(SHARED_LIBS): %.so: %_sh.o + $(LD) $(LDFLAGS) -shared -o $@ $< -lc $(filter-out -ldl,$(LIBS)) $(MYSQL_LDFLAGS) + +%_sh.o: %.c + $(CC) $(MYSQL_CFLAGS) $(SH_CFLAGS) -o $@ -c $< + +netflow-import: ulogd_NETFLOW.c + $(CC) $(MYSQL_CFLAGS) $(SH_CFLAGS) -DSTANDALONE -o $@ $< $(MYSQL_LDFLAGS) -lpthread + +clean: + $(RM) $(SHARED_LIBS) *.o + +distclean: + $(RM) Makefile + +install: all + $(INSTALL) -m 755 -d $(DESTDIR)$(ULOGD_LIB_PATH) + $(INSTALL) -m 755 *.so $(DESTDIR)$(ULOGD_LIB_PATH) + $(INSTALL) -D -m 755 netflow-import $(DESTDIR)/$(bindir)/netflow-import diff --git a/netflow/ulogd_NETFLOW.c b/netflow/ulogd_NETFLOW.c new file mode 100644 index 0000000..5e7046e --- /dev/null +++ b/netflow/ulogd_NETFLOW.c @@ -0,0 +1,1512 @@ +/* + * ulogd output target for IP flow analysis + * + * Mark Huang + * Copyright (C) 2004-2005 The Trustees of Princeton University + * + * Based on admindump.pl by Mic Bowman and Paul Brett + * Copyright (c) 2002 Intel Corporation + * + * $Id: ulogd_NETFLOW.c,v 1.19 2005/04/20 21:10:05 mlhuang Exp $ + */ + +/* Enable GNU glibc extensions */ +#define _GNU_SOURCE + +#include +#include + +/* va_start() and friends */ +#include + +/* ispunct() */ +#include + +/* strstr() and friends */ +#include + +/* dirname() and basename() */ +#include + +/* fork() and wait() */ +#include +#include +#include + +/* fgetpwent() */ +#include + +/* errno and assert() */ +#include +#include + +/* getopt_long() */ +#include + +/* time() and friends */ +#include +#include + +/* inet_aton() */ +#include +#include +#include + +/* ICMP definitions */ +#include +#include + +/* stat() */ +#include + +/* pthread_create() */ +#include + +/* flock() */ +#include + +#include +#include + +#if !defined(STANDALONE) && HAVE_LIBPROPER +#include +#endif + +/* + * /etc/ulogd.conf configuration options + */ + +/* Dump interval in minutes */ +static config_entry_t interval = { + .next = NULL, + .key = "interval", + .type = CONFIG_TYPE_INT, + .options = CONFIG_OPT_NONE, + .u = { .value = 5 }, +}; + +/* Slice map (in /etc/passwd format) */ +static config_entry_t slicemap = { + .next = &interval, + .key = "slicemap", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_NONE, + .u = { .string = "/etc/passwd" }, +}; + +/* MySQL database name */ +static config_entry_t mysqldb = { + .next = &slicemap, + .key = "mysqldb", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_NONE, + .u = { .string = "netflow" }, +}; + +/* MySQL database user */ +static config_entry_t mysqluser = { + .next = &mysqldb, + .key = "mysqluser", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_NONE, + .u = { .string = "netflow" }, +}; + +/* MySQL database password */ +static config_entry_t mysqlpass = { + .next = &mysqluser, + .key = "mysqlpass", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_NONE, + .u = { .string = "" }, +}; + +/* MySQL database host */ +static config_entry_t mysqlhost = { + .next = &mysqlpass, + .key = "mysqlhost", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_NONE, + .u = { .string = "" }, +}; + +/* Latest flows in CSV format */ +static config_entry_t csv = { + .next = &mysqlhost, + .key = "csv", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_NONE, + .u = { .string = "/var/www/html/flows.csv" }, +}; + +#define config_entries (&csv) + +/* + * Debug functionality + */ + +#ifdef DMALLOC +#include +#endif + +#define NIPQUAD(addr) \ + ((unsigned char *)&addr)[0], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[3] + +#define IPQUAD(addr) \ + ((unsigned char *)&addr)[3], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[0] + +/* + * MySQL support + */ + +#include + +/* mysql_query() with printf() syntax */ +static int +mysql_queryf(MYSQL *dbh, const char *fmt, ...) +{ + char *buf = NULL; + size_t len; + va_list ap; + int ret = 2 * strlen(fmt); + + do { + len = ret + 1; + if (!(buf = realloc(buf, len))) { + ulogd_log(ULOGD_ERROR, "realloc: %s\n", strerror(errno)); + ret = -errno; + goto done; + } + va_start(ap, fmt); + ret = vsnprintf(buf, len, fmt, ap); + va_end(ap); + if (ret < 0) { + ulogd_log(ULOGD_ERROR, "vsnprintf: %s\n", strerror(errno)); + goto done; + } + } while (ret >= len); + + ret = mysql_query(dbh, buf); + if (ret) + ulogd_log(ULOGD_ERROR, "%s: %s\n", buf, mysql_error(dbh)); + + done: + if (buf) + free(buf); + return ret; +} + +/* + * Jenkins hash support + */ + +typedef u_int8_t u8; +typedef u_int16_t u16; +typedef u_int32_t u32; +#include + +/* Salt for the hash functions */ +static int salt; + +/* + * Hash slice name lookups on context ID. + */ + +/* Special context IDs */ +#define UNKNOWN_XID -1 +#define ROOT_XID 0 + +enum { + CONNECTION_REFUSED_XID = 65536, /* MAX_S_CONTEXT + 1 */ + ICMP_ECHOREPLY_XID, + ICMP_UNREACH_XID, +}; + +/* A slice */ +struct slice { + struct slice *next; + int xid; + char *name; +}; + +/* Must be a power of 2 */ +#define SLICE_HASH_SIZE 128 +struct slice *slice_hash[SLICE_HASH_SIZE]; + +static inline int +hash_slice(int xid) +{ + return jhash_1word(xid, salt) & (SLICE_HASH_SIZE - 1); +} + +static struct slice * +get_slice(int xid) +{ + struct slice *slice; + int i; + + i = hash_slice(xid); + for (slice = slice_hash[i]; slice; slice = slice->next) { + if (slice->xid == xid) + break; + } + + return slice; +} + +static struct slice * +add_slice(int xid, char *name) +{ + struct slice *slice; + int i; + + slice = malloc(sizeof(struct slice)); + if (!slice) + return NULL; + memset(slice, 0, sizeof(struct slice)); + + slice->xid = xid; + slice->name = strdup(name); + if (!slice->name) { + free(slice); + return NULL; + } + + /* Add to hashed list */ + i = hash_slice(xid); + slice->next = slice_hash[i]; + slice_hash[i] = slice; + + return slice; +} + +static int +hash_passwd(void) +{ + int fd; + FILE *fp; + struct passwd *pw; + struct slice *slice, *next; + int i; + +#if !defined(STANDALONE) && HAVE_LIBPROPER + if ((fd = prop_open_file(slicemap.u.string, PROP_OPEN_READ)) < 0) { + /* prop_open_file() returns -errno */ + errno = -fd; + } +#else + fd = open(slicemap.u.string, O_RDONLY); +#endif + + if (fd < 0 || !(fp = fdopen(fd, "r"))) { + ulogd_log(ULOGD_ERROR, "%s: %s\n", slicemap.u.string, strerror(errno)); + if (fd >= 0) + close(fd); + return errno; + } + + /* Clean hash */ + for (i = 0; i < SLICE_HASH_SIZE; i++) { + for (slice = slice_hash[i]; slice; slice = next) { + next = slice->next; + assert(slice->name); + free(slice->name); + free(slice); + } + slice_hash[i] = NULL; + } + + /* (Re)build slice hash */ + while ((pw = fgetpwent(fp))) + add_slice(pw->pw_uid, pw->pw_name); + + fclose(fp); + close(fd); + return 0; +} + +/* + * Maintain flows in a two level hash table. The first level hashes + * on (src_ip, slice). The second level hashes on (protocol, dst_ip, + * src_port, dst_port). This structure mirrors how we store flows in + * the database (in many tables where each table contains flows with + * the same (src_ip, slice) parameters and unique (protocol, + * src_port, dst_ip, dst_port) rows). + */ + +/* Must be powers of 2 */ +#ifdef STANDALONE +#define TABLE_HASH_SIZE 16 +#define FLOW_HASH_SIZE 65536 +#else +#define TABLE_HASH_SIZE 8 +#define FLOW_HASH_SIZE 1024 +#endif + +struct flow { + struct flow *nexth; /* Next in hash */ + struct flow *next; /* Next in ordered list */ + struct flow_table *table; /* Back pointer */ + u_int8_t protocol; /* IP protocol number */ + u_int16_t src_port; /* IP source port (host order) */ + u_int16_t dst_port; /* IP destination port (host order) */ + u_int32_t dst_ip; /* IP destination address (host order) */ + time_t start_time; /* Timestamp of the first packet in the flow */ + time_t end_time; /* Timestamp of the first packet in the flow */ + unsigned long long packets; /* Number of IP packets */ + unsigned long long bytes; /* Number of IP bytes (including headers) */ +}; + +struct flow_table { + struct flow_table *nexth; /* Next in hash */ + struct flow_table *next; /* Next in ordered list */ + u_int32_t src_ip; /* IP source address (host order) */ + int xid; /* Context ID */ + char slice[32]; /* Slice name */ + unsigned long rows; /* Total number of rows to insert/update */ + unsigned long collisions; /* Total number of row hash collisions */ + unsigned long long packets; /* Total number of packets sent in all flows in this table */ + unsigned long long bytes; /* Total number of bytes sent in all flows in this table */ + time_t start_time; /* Start time of the earliest flow in the table */ + time_t end_time; /* End time of the latest flow in the table */ + /* Hashed list of flows */ + struct flow *flows[FLOW_HASH_SIZE]; + /* Ordered list of flows */ + struct flow *flows_head, *flows_tail; +}; + +/* Hashed list of flow tables */ +static struct flow_table *flow_tables[TABLE_HASH_SIZE]; +/* Ordered list of flow tables */ +static struct flow_table *flow_tables_head, *flow_tables_tail; + +/* Maximum total number of outstanding allocated flows */ +#define MAX_FLOWS 65536 /* ip_conntrack_max on a 1 GB machine */ +static int flows; + +/* Double buffer the ordered list and dump it in another thread */ +static struct flow_table *dump_head, *dump_tail; +static int dump_flows; +static pthread_t dump_thread; + +static inline int +hash_flow_table(u_int32_t src_ip, int xid, char *slice) +{ + if (slice) + return jhash(slice, strlen(slice), salt) & (TABLE_HASH_SIZE - 1); + else + return jhash_2words(src_ip, xid, salt) & (TABLE_HASH_SIZE - 1); +} + +static struct flow_table * +get_flow_table(u_int32_t src_ip, int xid, char *slice) +{ + struct flow_table *flow_table; + int i; + + /* See if it already exists */ + i = hash_flow_table(src_ip, xid, slice); + for (flow_table = flow_tables[i]; flow_table; flow_table = flow_table->nexth) { + if (flow_table->src_ip == src_ip && + flow_table->xid == xid && + (!slice || !strncmp(flow_table->slice, slice, sizeof(flow_table->slice) - 1))) + break; + } + + if (!flow_table) { + /* Allocate a new flow table */ + flow_table = malloc(sizeof(struct flow_table)); + if (!flow_table) { + ulogd_log(ULOGD_ERROR, "malloc: %s\n", strerror(errno)); + return NULL; + } + + /* Initialize */ + memset(flow_table, 0, sizeof(struct flow_table)); + flow_table->src_ip = src_ip; + flow_table->xid = xid; + if (slice) + strncpy(flow_table->slice, slice, sizeof(flow_table->slice) - 1); + + /* Add to hashed list */ + i = hash_flow_table(src_ip, xid, slice); + flow_table->nexth = flow_tables[i]; + flow_tables[i] = flow_table; + + /* Add to ordered list */ + if (flow_tables_tail) { + assert(flow_tables_head); + flow_tables_tail->next = flow_table; + flow_tables_tail = flow_table; + } else { + assert(!flow_tables_head); + flow_tables_head = flow_tables_tail = flow_table; + } + } + + assert(flow_table); + assert(flow_table->src_ip == src_ip); + assert(flow_table->xid == xid); + assert(!slice || !strncmp(flow_table->slice, slice, sizeof(flow_table->slice) - 1)); + + return flow_table; +} + +static inline int +hash_flow(u_int8_t protocol, u_int16_t src_port, u_int32_t dst_ip, u_int16_t dst_port) +{ + return jhash_3words(protocol, dst_ip, (src_port << 16) | dst_port, salt) & (FLOW_HASH_SIZE - 1); +} + +static struct flow * +get_flow(u_int32_t src_ip, int xid, char *slice, + u_int8_t protocol, u_int16_t src_port, u_int32_t dst_ip, u_int16_t dst_port) +{ + struct flow_table *flow_table; + struct flow *flow; + int i; + + if (xid != UNKNOWN_XID) + flow_table = get_flow_table(src_ip, xid, slice); + else { + /* Support searching for flows without specifying a context ID */ + flow_table = flow_tables_head; + } + + for (; flow_table; flow_table = flow_table->next) { + i = hash_flow(protocol, src_port, dst_ip, dst_port); + for (flow = flow_table->flows[i]; flow; flow = flow->nexth) { + if (flow->protocol == protocol && + flow->src_port == src_port && + flow->dst_ip == dst_ip && + flow->dst_port == dst_port) + break; + } + if (xid != UNKNOWN_XID) + break; + } + + if (!flow_table) + return NULL; + + if (!flow) { + /* Allocate a new flow */ + flow = malloc(sizeof(struct flow)); + if (!flow) { + ulogd_log(ULOGD_ERROR, "malloc: %s\n", strerror(errno)); + return NULL; + } + + /* Initialize */ + memset(flow, 0, sizeof(struct flow)); + flow->table = flow_table; + flow->protocol = protocol; + flow->src_port = src_port; + flow->dst_ip = dst_ip; + flow->dst_port = dst_port; + + /* Add to hashed list */ + i = hash_flow(protocol, src_port, dst_ip, dst_port); + flow->nexth = flow_table->flows[i]; + flow_table->flows[i] = flow; + + /* Add to ordered list */ + if (flow_table->flows_tail) { + assert(flow_table->flows_head); + flow_table->flows_tail->next = flow; + flow_table->flows_tail = flow; + } else { + assert(!flow_table->flows_head); + flow_table->flows_head = flow_table->flows_tail = flow; + } + + /* Update table statistics */ + flow_table->collisions += flow->nexth ? 1 : 0; + flow_table->rows++; + + /* Update total number of outstanding flows */ + flows++; + } + + assert(flow); + assert(flow->table == flow_table); + assert(flow->protocol == protocol); + assert(flow->src_port == src_port); + assert(flow->dst_ip == dst_ip); + assert(flow->dst_port == dst_port); + + return flow; +} + +/* + * The dump thread imports one set of flows while the collection + * thread continues to record new flows. + */ + +void * +dump_interval(void *unused) +{ + MYSQL *dbh; + struct flow_table *flow_table, *next_flow_table; + struct flow *flow, *next_flow, bind_flow; + struct slice *slice; + char slice_name[64]; + char table_name[NAME_LEN + 1], *c; + struct tm tm; + MYSQL_STMT *stmt; + char query[512]; + unsigned int tables, table_collisions, row_collisions, rows; + unsigned long long packets, bytes; + struct timeval start, end, interval_start; + int fd; + FILE *fp; + + /* Time this interval */ + gettimeofday(&interval_start, NULL); + + /* Hash slice name lookups */ + hash_passwd(); + + /* Open, lock, and truncate CSV file */ + if ((fd = open(csv.u.string, O_CREAT | O_WRONLY, 0644)) >= 0) { + int tries = 10; + + while (flock(fd, LOCK_EX | LOCK_NB)) { + sleep(1); + tries--; + } + if (tries == 0) + ulogd_log(ULOGD_ERROR, "Could not acquire lock on %s\n", csv.u.string); + if (!(fp = fdopen(fd, "w"))) + close(fd); + else + ftruncate(fd, 0); + } else + fp = NULL; + + /* Connect to DB */ + if (!(dbh = mysql_init(NULL))) + ulogd_log(ULOGD_ERROR, "mysql_init: failed\n"); + if (dbh && !mysql_real_connect(dbh, + mysqlhost.u.string[0] ? mysqlhost.u.string : NULL, + mysqluser.u.string, + mysqlpass.u.string[0] ? mysqlpass.u.string : NULL, + mysqldb.u.string, + 0, NULL, 0)) { + ulogd_log(ULOGD_ERROR, + "%s@%s:%s: %s\n", + mysqluser.u.string, + mysqlhost.u.string[0] ? mysqlhost.u.string : "localhost", + mysqldb.u.string, + mysql_error(dbh)); + mysql_close(dbh); + dbh = NULL; + } + + if (dbh) { + /* All times in the database are in GMT */ + mysql_query(dbh, "SET time_zone='+00:00'"); + } + + /* Initialize statistics */ + tables = table_collisions = row_collisions = rows = 0; + packets = bytes = 0; + + assert(dump_head); + + for (flow_table = dump_head; flow_table; flow_table = next_flow_table) { + /* Keep track of some basic statistics */ + tables++; + table_collisions += flow_table->nexth ? 1 : 0; + row_collisions += flow_table->collisions; + rows += flow_table->rows; + packets += flow_table->packets; + bytes += flow_table->bytes; + + /* Get slice name */ + slice_name[sizeof(slice_name) - 1] = '\0'; + switch (flow_table->xid) { + case CONNECTION_REFUSED_XID: + strncpy(slice_name, "connection-refused", sizeof(slice_name)); + break; + case ICMP_ECHOREPLY_XID: + strncpy(slice_name, "icmp-reply", sizeof(slice_name)); + break; + case ICMP_UNREACH_XID: + strncpy(slice_name, "icmp-unreachable", sizeof(slice_name)); + break; + default: + if ((slice = get_slice(flow_table->xid))) + strncpy(slice_name, slice->name, sizeof(slice_name)); + else if (flow_table->slice[0]) + strncpy(slice_name, flow_table->slice, sizeof(slice_name)); + else + snprintf(slice_name, sizeof(slice_name), "%u", flow_table->xid); + break; + } + + if (dbh) { + /* Get day */ + gmtime_r(&flow_table->start_time, &tm); + + /* Form a human readable table name */ + snprintf(table_name, sizeof(table_name), + "%u_%u_%u_%u_%s_%u_%02u_%02u", + IPQUAD(flow_table->src_ip), + slice_name, + 1900 + tm.tm_year, tm.tm_mon + 1, tm.tm_mday); + assert(strlen(table_name) <= NAME_LEN); + + /* Replace punctation with underscores */ + for (c = table_name; *c; c++) { + if (ispunct(*c)) + *c = '_'; + } + + /* Time database operations on each table */ + gettimeofday(&start, NULL); + + /* Insert/update table summary */ + if (mysql_queryf(dbh, + "INSERT INTO flow_tables " + "(table_name,src_ip,slice," + "start_time,end_time,packets,bytes) " + "VALUES ('%s',%u,'%s'," + "FROM_UNIXTIME(%u),FROM_UNIXTIME(%u),%llu,%llu) " + "ON DUPLICATE KEY UPDATE " + "end_time=FROM_UNIXTIME(%u)," + "packets=packets+%llu," + "bytes=bytes+%llu", + table_name, + flow_table->src_ip, + slice_name, + (unsigned) flow_table->start_time, + (unsigned) flow_table->end_time, + flow_table->packets, + flow_table->bytes, + (unsigned) flow_table->end_time, + flow_table->packets, + flow_table->bytes)) + goto free_flow_table; + + /* Create table */ + if (mysql_queryf(dbh, + "CREATE TABLE IF NOT EXISTS %s LIKE flow_template", + table_name)) + goto free_flow_table; + + /* Lock for speed */ + mysql_queryf(dbh, "ALTER TABLE %s DISABLE KEYS", table_name); + mysql_queryf(dbh, "LOCK TABLES %s WRITE", table_name); + + /* Prepare the insert statement */ + if (!(stmt = mysql_stmt_init(dbh))) + ulogd_log(ULOGD_ERROR, "mysql_stmt_init: %s\n", mysql_error(dbh)); + else { + my_bool is_null = 0; + MYSQL_BIND bind[] = { + { .buffer_type = MYSQL_TYPE_TINY, + .buffer = &bind_flow.protocol, + .buffer_length = sizeof(bind_flow.protocol), + .length = &bind[0].buffer_length, + .is_null = &is_null, + .is_unsigned = 1, }, + { .buffer_type = MYSQL_TYPE_SHORT, + .buffer = &bind_flow.src_port, + .buffer_length = sizeof(bind_flow.src_port), + .length = &bind[1].buffer_length, + .is_null = &is_null, + .is_unsigned = 1, }, + { .buffer_type = MYSQL_TYPE_LONG, + .buffer = &bind_flow.dst_ip, + .buffer_length = sizeof(bind_flow.dst_ip), + .length = &bind[2].buffer_length, + .is_null = &is_null, + .is_unsigned = 1, }, + { .buffer_type = MYSQL_TYPE_SHORT, + .buffer = &bind_flow.dst_port, + .buffer_length = sizeof(bind_flow.dst_port), + .length = &bind[3].buffer_length, + .is_null = &is_null, + .is_unsigned = 1, }, + { .buffer_type = MYSQL_TYPE_LONG, + .buffer = &bind_flow.start_time, + .buffer_length = sizeof(bind_flow.start_time), + .length = &bind[4].buffer_length, + .is_null = &is_null, + .is_unsigned = 1, }, + { .buffer_type = MYSQL_TYPE_LONG, + .buffer = &bind_flow.end_time, + .buffer_length = sizeof(bind_flow.end_time), + .length = &bind[5].buffer_length, + .is_null = &is_null, + .is_unsigned = 1, }, + { .buffer_type = MYSQL_TYPE_LONGLONG, + .buffer = &bind_flow.packets, + .buffer_length = sizeof(bind_flow.packets), + .length = &bind[6].buffer_length, + .is_null = &is_null, + .is_unsigned = 1, }, + { .buffer_type = MYSQL_TYPE_LONGLONG, + .buffer = &bind_flow.bytes, + .buffer_length = sizeof(bind_flow.bytes), + .length = &bind[7].buffer_length, + .is_null = &is_null, + .is_unsigned = 1, }, + { .buffer_type = MYSQL_TYPE_LONG, + .buffer = &bind_flow.end_time, + .buffer_length = sizeof(bind_flow.end_time), + .length = &bind[8].buffer_length, + .is_null = &is_null, + .is_unsigned = 1, }, + { .buffer_type = MYSQL_TYPE_LONGLONG, + .buffer = &bind_flow.packets, + .buffer_length = sizeof(bind_flow.packets), + .length = &bind[9].buffer_length, + .is_null = &is_null, + .is_unsigned = 1, }, + { .buffer_type = MYSQL_TYPE_LONGLONG, + .buffer = &bind_flow.bytes, + .buffer_length = sizeof(bind_flow.bytes), + .length = &bind[10].buffer_length, + .is_null = &is_null, + .is_unsigned = 1, }, + }; + + snprintf(query, sizeof(query), + "INSERT INTO %s " + "(protocol,src_port,dst_ip,dst_port," + "start_time,end_time,packets,bytes) " + "VALUES (?,?,?,?," + "FROM_UNIXTIME(?),FROM_UNIXTIME(?),?,?) " + "ON DUPLICATE KEY UPDATE " + "end_time=FROM_UNIXTIME(?)," + "packets=packets+?," + "bytes=bytes+?", + table_name); + + if (mysql_stmt_prepare(stmt, query, strlen(query)) || + mysql_stmt_bind_param(stmt, bind)) { + ulogd_log(ULOGD_ERROR, "%s: %s\n", query, mysql_stmt_error(stmt)); + mysql_stmt_close(stmt); + stmt = NULL; + } + } + } else + stmt = NULL; + + for (flow = flow_table->flows_head; flow; flow = flow->next) { + /* Dump to CSV */ + if (fp) { + fprintf(fp, + "%s,%u," + "%u.%u.%u.%u,%u," + "%u.%u.%u.%u,%u," + "%u,%u,%llu,%llu\n", + slice_name, flow->protocol, + IPQUAD(flow_table->src_ip), flow->src_port, + IPQUAD(flow->dst_ip), flow->dst_port, + (unsigned) flow->start_time, + (unsigned) flow->end_time, + flow->packets, + flow->bytes); + } + + /* Insert/update flow record */ + if (dbh) { + if (stmt) { + bind_flow = *flow; + if (mysql_stmt_execute(stmt)) + ulogd_log(ULOGD_ERROR, "%s: %s\n", query, mysql_stmt_error(stmt)); + } else { + mysql_queryf(dbh, + "INSERT INTO %s " + "(protocol,src_port,dst_ip,dst_port," + "start_time,end_time,packets,bytes) " + "VALUES (%u,%u,%u,%u," + "FROM_UNIXTIME(%u),FROM_UNIXTIME(%u),%llu,%llu) " + "ON DUPLICATE KEY UPDATE " + "end_time=FROM_UNIXTIME(%u)," + "packets=packets+%llu," + "bytes=bytes+%llu", + table_name, + flow->protocol, + flow->src_port, + flow->dst_ip, + flow->dst_port, + (unsigned) flow->start_time, + (unsigned) flow->end_time, + flow->packets, + flow->bytes, + (unsigned) flow->end_time, + flow->packets, + flow->bytes); + } + } + } + + if (dbh) { + if (stmt) + mysql_stmt_close(stmt); + + /* Unlock */ + mysql_query(dbh, "UNLOCK TABLES"); + mysql_queryf(dbh, "ALTER TABLE %s ENABLE KEYS", table_name); + + /* Update table summary */ + mysql_queryf(dbh, + "UPDATE flow_tables " + "SET flows=(SELECT COUNT(protocol) FROM %s) " + "WHERE table_name='%s'", + table_name, + table_name); + + gettimeofday(&end, NULL); + timersub(&end, &start, &end); + } + + ulogd_log(ULOGD_DEBUG, + "Updated %u rows in %s in %u.%06u s (%u collisions, %llu packets, %llu bytes)\n", + flow_table->rows, table_name, + (unsigned) end.tv_sec, (unsigned) end.tv_usec, + flow_table->collisions, flow_table->packets, flow_table->bytes); + + free_flow_table: + for (flow = flow_table->flows_head; flow; flow = next_flow) { + flow_table->rows--; + flow_table->packets -= flow->packets; + flow_table->bytes -= flow->bytes; + dump_flows--; + next_flow = flow->next; + assert(next_flow || flow == flow_table->flows_tail); + free(flow); + } + + assert(!flow_table->rows); + assert(!flow_table->packets); + assert(!flow_table->bytes); + + next_flow_table = flow_table->next; + assert(next_flow_table || flow_table == dump_tail); + free(flow_table); + } + + assert(!dump_flows); + dump_head = dump_tail = NULL; + + if (dbh) { + mysql_close(dbh); + + gettimeofday(&end, NULL); + timersub(&end, &interval_start, &end); + + ulogd_log(ULOGD_NOTICE, + "Updated %u rows in %u tables (%u bytes) in %u.%06u s " + "(%u table collisions, %u row collisions, %llu packets, %llu bytes)\n", + rows, tables, tables * sizeof(struct flow_table) + flows * sizeof(struct flow), + (unsigned) end.tv_sec, (unsigned) end.tv_usec, + table_collisions, row_collisions, packets, bytes); + } else { + /* Could not connect to database */ + ulogd_log(ULOGD_ERROR, + "Lost %u rows in %u tables (%u bytes) " + "(%u table collisions, %u row collisions, %llu packets, %llu bytes)\n", + rows, tables, tables * sizeof(struct flow_table) + flows * sizeof(struct flow), + table_collisions, row_collisions, packets, bytes); + } + + if (fp) { + fclose(fp); + assert(fd >= 0); + close(fd); + } + + pthread_exit(NULL); + return NULL; +} + +static void +start_dump(void) +{ + /* Wait for previous dump thread to complete */ + if (dump_thread) { + pthread_join(dump_thread, NULL); + dump_thread = 0; + } + + /* Switch buffers */ + assert(!dump_head); + assert(!dump_tail); + assert(!dump_flows); + dump_head = flow_tables_head; + dump_tail = flow_tables_tail; + dump_flows = flows; + + /* Start up the dump thread if necessary */ + if (pthread_create(&dump_thread, NULL, dump_interval, NULL)) { + ulogd_log(ULOGD_ERROR, "pthread_create: %s\n", strerror(errno)); + /* Try again later */ + dump_thread = 0; + dump_head = dump_tail = NULL; + dump_flows = 0; + } else { + /* Clear hash */ + memset(flow_tables, 0, sizeof(flow_tables)); + flow_tables_head = flow_tables_tail = NULL; + flows = 0; + } +} + +static void +update_flow(struct flow *flow, time_t now, unsigned int packets, unsigned int bytes) +{ + /* Update flow */ + if (now > flow->end_time) + flow->end_time = now; + if (!flow->start_time || now < flow->start_time) + flow->start_time = now; + flow->packets += packets; + flow->bytes += bytes; + + /* Update table summary */ + if (now > flow->table->end_time) + flow->table->end_time = now; + if (!flow->table->start_time || now < flow->table->start_time) + flow->table->start_time = now; + flow->table->packets += packets; + flow->table->bytes += bytes; +} + +#ifndef STANDALONE + +struct intr_id { + char* name; + ulog_iret_t *res; +}; + +/* Interesting keys */ +enum { + OOB_TIME_SEC = 0, + OOB_MARK, + IP_SADDR, + IP_DADDR, + IP_TOTLEN, + IP_PROTOCOL, + TCP_SPORT, + TCP_DPORT, + TCP_ACK, + TCP_RST, + UDP_SPORT, + UDP_DPORT, + ICMP_TYPE, + ICMP_CODE, + GRE_FLAG_KEY, + GRE_VERSION, + GRE_KEY, + PPTP_CALLID, +}; + +#define INTR_IDS (sizeof(intr_ids)/sizeof(intr_ids[0])) +static struct intr_id intr_ids[] = { + [OOB_TIME_SEC] = { "oob.time.sec", 0 }, + [OOB_MARK] = { "oob.mark", 0 }, + [IP_SADDR] = { "ip.saddr", 0 }, + [IP_DADDR] = { "ip.daddr", 0 }, + [IP_TOTLEN] = { "ip.totlen", 0 }, + [IP_PROTOCOL] = { "ip.protocol", 0 }, + [TCP_SPORT] = { "tcp.sport", 0 }, + [TCP_DPORT] { "tcp.dport", 0 }, + [TCP_ACK] = { "tcp.ack", 0 }, + [TCP_RST] = { "tcp.rst", 0 }, + [UDP_SPORT] = { "udp.sport", 0 }, + [UDP_DPORT] = { "udp.dport", 0 }, + [ICMP_TYPE] = { "icmp.type", 0 }, + [ICMP_CODE] = { "icmp.code", 0 }, + [GRE_FLAG_KEY] = { "gre.flag.key", 0 }, + [GRE_VERSION] = { "gre.version", 0 }, + [GRE_KEY] = { "gre.key", 0 }, + [PPTP_CALLID] = { "pptp.callid", 0 }, +}; + +#define GET_VALUE(x) intr_ids[x].res->value + +#define DATE(t) ((t) / (24*60*60) * (24*60*60)) + +static int _output_netflow(ulog_iret_t *res) +{ + u_int8_t protocol; + u_int32_t src_ip, dst_ip; + u_int16_t src_port, dst_port; + int xid; + struct flow *flow = NULL; + time_t now; + + now = (time_t) GET_VALUE(OOB_TIME_SEC).ui32; + + if (flow_tables_head) { + /* If we have collected for at least 5 minutes, or + * collected the maximum number of flows, or it is now + * the next day, dump this interval. + */ + if ((now - flow_tables_head->start_time) >= (interval.u.value * 60) || + flows >= MAX_FLOWS || + DATE(flow_tables_head->start_time) != DATE(now)) { + /* Out of memory */ + if (flows >= MAX_FLOWS) + ulogd_log(ULOGD_ERROR, "dumping %d flows early\n", flows); + + start_dump(); + } + } + + protocol = GET_VALUE(IP_PROTOCOL).ui8; + src_ip = GET_VALUE(IP_SADDR).ui32; + dst_ip = GET_VALUE(IP_DADDR).ui32; + xid = GET_VALUE(OOB_MARK).ui32; + + switch (protocol) { + + case IPPROTO_TCP: + src_port = GET_VALUE(TCP_SPORT).ui16; + dst_port = GET_VALUE(TCP_DPORT).ui16; + + /* check for root termination */ + if (xid == ROOT_XID) { + if ((flow = get_flow(src_ip, UNKNOWN_XID, NULL, protocol, src_port, dst_ip, dst_port))) { + /* + * this is supposed to catch some of the cases where the + * network stack responds on behalf of the user but the + * slice is incorrectly accounted for, e.g. on socket + * shutdown + */ + assert(flow->table); + xid = flow->table->xid; + } else { + /* + * we have not seen any packets on this flow during the + * current interval, check for the connection refused + */ + if (GET_VALUE(TCP_RST).b && GET_VALUE(TCP_ACK).b) + xid = CONNECTION_REFUSED_XID; + } + } + break; + + case IPPROTO_UDP: + /* + * we could record the source port, however this pretty much + * kills any notion of UDP flows and therefore consume large + * quantities of space, so we set the source port to 0 + * tuple.sport = GET_VALUE(UDP_SPORT).ui16; + */ + src_port = 0; + + /* + * traceroutes create a large number of flows in the db + * this is a quick hack to catch the most common form + * of traceroute (basically we're mapping any UDP packet + * in the 33435-33524 range to the "trace" port, 33524 is + * 3 packets * nhops (30). + */ + dst_port = GET_VALUE(UDP_DPORT).ui16; + if (dst_port >= 33435 && dst_port <= 33524) + dst_port = 33435; + break; + + case IPPROTO_ICMP: + src_port = GET_VALUE(ICMP_TYPE).ui8; + dst_port = GET_VALUE(ICMP_CODE).ui8; + + /* + * We special case some of the ICMP traffic that the kernel + * always generates. Since this is attributed to root, it + * creates significant "noise" in the output. We want to be + * able to quickly see that root is generating traffic. + */ + if (xid == ROOT_XID) { + if (src_port == ICMP_ECHOREPLY) + xid = ICMP_ECHOREPLY_XID; + else if (src_port == ICMP_UNREACH) + xid = ICMP_UNREACH_XID; + } + break; + + case IPPROTO_GRE: + if (GET_VALUE(GRE_FLAG_KEY).b) { + if (GET_VALUE(GRE_VERSION).ui8 == 1) { + /* Get PPTP call ID */ + src_port = GET_VALUE(PPTP_CALLID).ui16; + } else { + /* XXX Truncate GRE keys to 16 bits */ + src_port = (u_int16_t) GET_VALUE(GRE_KEY).ui32; + } + } else { + /* No key available */ + src_port = 0; + } + dst_port = 0; + break; + + default: + /* This is the default key for packets from unsupported protocols */ + src_port = 0; + dst_port = 0; + break; + } + + /* Record the flow */ + if (!flow) { + flow = get_flow(src_ip, xid, NULL, protocol, src_port, dst_ip, dst_port); + if (!flow) + return -ENOMEM; + } + + /* Update the flow */ + update_flow(flow, now, 1, GET_VALUE(IP_TOTLEN).ui16); + + return 0; +} + +/* get all key id's for the keys we are intrested in */ +static int get_ids(void) +{ + int i; + struct intr_id *cur_id; + + for (i = 0; i < INTR_IDS; i++) { + cur_id = &intr_ids[i]; + cur_id->res = keyh_getres(keyh_getid(cur_id->name)); + if (!cur_id->res) { + ulogd_log(ULOGD_ERROR, + "Cannot resolve keyhash id for %s\n", + cur_id->name); + return 1; + } + } + return 0; +} + + +static int _netflow_init(void) +{ + /* have the opts parsed */ + config_parse_file("NETFLOW",config_entries); + + if (get_ids()) { + ulogd_log(ULOGD_ERROR, "can't resolve all keyhash id's\n"); + exit(2); + } + + /* Seed the hash function */ + salt = getpid() ^ time(NULL); + + return 0; +} + + +static void _netflow_fini(void) +{ + /* should probably stop the dump thread?! */ + + /* do nothing */ +} + + +static ulog_output_t netflow_op = { + .name = "netflow", + .output = &_output_netflow, + .init = _netflow_init, + .fini = _netflow_fini, +}; + +void _init(void) +{ + register_output(&netflow_op); +} + +#else + +static FILE *logfile = NULL; /* logfile pointer */ +static int loglevel = 5; /* current loglevel */ + +/* log message to the logfile */ +void __ulogd_log(int level, char *file, int line, const char *format, ...) +{ + char *timestr; + va_list ap; + time_t tm; + FILE *outfd; + + /* log only messages which have level at least as high as loglevel */ + if (level < loglevel) + return; + + if (logfile) + outfd = logfile; + else + outfd = stderr; + + va_start(ap, format); + + tm = time(NULL); + timestr = ctime(&tm); + timestr[strlen(timestr)-1] = '\0'; + fprintf(outfd, "%s <%1.1d> %s:%d ", timestr, level, file, line); + + vfprintf(outfd, format, ap); + va_end(ap); + + /* flush glibc's buffer */ + fflush(outfd); +} + +int +main(int argc, char **argv) +{ + /* Get options */ + while (1) { + int option_index = 0; + static struct option long_options[] = { + { "user", required_argument, NULL, 'u' }, + { "database", required_argument, NULL, 'd' }, + { "password", required_argument, NULL, 'p' }, + { "verbose", required_argument, NULL, 'v' }, + { "host", required_argument, NULL, 'h' }, + { "help", required_argument, NULL, '?' }, + { 0, 0, 0, 0 } + }; + struct option *opt; + int c; + + c = getopt_long(argc, argv, "u:d:p:v:h:", long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 'u': + strncpy(mysqluser.u.string, optarg, sizeof(mysqluser.u.string)); + break; + case 'd': + strncpy(mysqldb.u.string, optarg, sizeof(mysqldb.u.string)); + break; + case 'p': + strncpy(mysqlpass.u.string, optarg, sizeof(mysqlpass.u.string)); + break; + case 'v': + loglevel = atoi(optarg); + break; + case 'h': + strncpy(mysqlhost.u.string, optarg, sizeof(mysqlhost.u.string)); + break; + default: + fprintf(stderr, "usage: %s [OPTION]... YY/mm-dd.log[.bz2|.gz]...\n", argv[0]); + for (opt = long_options; opt->name; opt++) + fprintf(stderr, "\t-%c, --%s%s\n", opt->val, opt->name, required_argument ? "=ARGUMENT" : ""); + return 1; + } + } + + /* Seed the hash function */ + salt = getpid() ^ time(NULL); + + /* Don't lookup slice names in /etc/passwd */ + strcpy(slicemap.u.string, "/dev/null"); + + /* All times in the log files are in GMT */ + putenv("TZ=GMT"); + + /* Parse the rest of the non-option arguments (files to import) */ + for (argv = &argv[optind]; *argv; argv++) { + char pathname[PATH_MAX], *s, *next; + const char *cmd = NULL, *opts = NULL; + pid_t pid = 0; + FILE *fp = NULL; + char *line = NULL; + size_t len = 0; + int fds[2] = { -1, -1 }; + time_t now; + struct tm tm; + + if (!realpath(*argv, pathname)) { + ulogd_log(ULOGD_ERROR, "%s: %s\n", *argv, strerror(errno)); + goto next_file; + } + + /* We may need to fork a child to decompress the log file */ + if (strstr(pathname, ".bz2")) { + cmd = "bzip2"; + opts = "-cdfq"; + } else if (strstr(pathname, ".gz")) { + cmd = "gzip"; + opts = "-cdfq"; + } else if (strstr(pathname, ".zip")) { + cmd = "unzip"; + opts = "-p"; + } + + /* Fork a child to decompress the log file */ + if (cmd) { + /* Open a pipe */ + if (pipe(fds)) { + ulogd_log(ULOGD_ERROR, "pipe: %s\n", strerror(errno)); + goto next_file; + } + switch ((pid = fork())) { + case -1: + ulogd_log(ULOGD_ERROR, "fork: %s\n", strerror(errno)); + goto next_file; + case 0: + close(fds[0]); + fds[0] = -1; + /* Redirect stdout to the write end of the pipe */ + if (dup2(fds[1], fileno(stdout)) < 0) { + ulogd_log(ULOGD_ERROR, "dup2: %s\n", strerror(errno)); + exit(errno); + } + execlp(cmd, cmd, opts, pathname, NULL); + ulogd_log(ULOGD_ERROR, "execlp: %s\n", strerror(errno)); + goto next_file; + default: + close(fds[1]); + fds[1] = -1; + /* Open the read end of the pipe */ + if (!(fp = fdopen(fds[0], "r"))) { + ulogd_log(ULOGD_ERROR, "fdopen: %s\n", strerror(errno)); + goto next_file; + } + break; + } + } + + /* Just open the file */ + else if (!(fp = fopen(pathname, "r"))) { + ulogd_log(ULOGD_ERROR, "%s: %s\n", pathname, strerror(errno)); + goto next_file; + } + + /* Parse date from the pathname (e.g. [.*]/05/01-25.log[.bz2|gz]) */ + now = time(NULL); + gmtime_r(&now, &tm); + + next = pathname; + while ((s = strsep(&next, "/"))) { + int mon, mday, year; + + if (sscanf(s, "%02u-%02u.log%*s", &mon, &mday) == 2) { + tm.tm_mon = mon - 1; + tm.tm_mday = mday; + } else if (strlen(s) == 2 && sscanf(s, "%02u", &year) == 1) { + /* Use strptime(3) strategy: ...values in the range + * 69-99 refer to years in the twentieth century + * (1969-1999); values in the range 00-68 refer to + * years in the twenty-first century (2000-2068). + */ + if (year < 69) + year += 100; + tm.tm_year = year; + } + } + + /* Reset to midnight and recalculate derived fields with mktime() */ + tm.tm_hour = tm.tm_min = tm.tm_sec = 0; + mktime(&tm); + + while (getline(&line, &len, fp) >= 0) { + char *s, *next; + char *slice; + u_int8_t protocol; + struct in_addr src_ip, dst_ip; + unsigned int src_port, dst_port; + unsigned int packets, bytes; + struct flow *flow; + + /* Parse the flow record */ + next = line; + + if (!(s = strsep(&next, ",")) || + sscanf(s, "%02u-%02u-%02u", &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 3) + continue; + now = mktime(&tm); + + if (!(s = strsep(&next, ","))) + continue; + if (!strcasecmp(s, "TCP")) + protocol = IPPROTO_TCP; + else if (!strcasecmp(s, "UDP")) + protocol = IPPROTO_UDP; + else if (!strcasecmp(s, "ICMP")) + protocol = IPPROTO_ICMP; + else if (!strcasecmp(s, "GRE")) + protocol = IPPROTO_GRE; + else + protocol = atoi(s); + + if (!(slice = strsep(&next, ","))) + continue; + + if (!(s = strsep(&next, ",")) || + !inet_aton(s, &src_ip)) + continue; + + if (!(s = strsep(&next, ",")) || + sscanf(s, "%u", &src_port) != 1) + continue; + + if (!(s = strsep(&next, ",")) || + !inet_aton(s, &dst_ip)) + continue; + + if (!(s = strsep(&next, ",")) || + sscanf(s, "%u", &dst_port) != 1) + continue; + + if (!(s = strsep(&next, ",")) || + sscanf(s, "%u", &packets) != 1) + continue; + + if (!(s = strsep(&next, ",")) || + sscanf(s, "%u", &bytes) != 1) + continue; + + /* Record the flow */ + flow = get_flow(ntohl(src_ip.s_addr), 0, slice, + protocol, src_port, ntohl(dst_ip.s_addr), dst_port); + if (!flow) + continue; + + /* Update flow */ + update_flow(flow, now, packets, bytes); + } + if (line) + free(line); + + start_dump(); + + next_file: + if (pid && kill(pid, SIGTERM)) + ulogd_log(ULOGD_ERROR, "kill: %s\n", strerror(errno)); + wait(NULL); + if (fp) + fclose(fp); + if (fds[0] >= 0) + close(fds[0]); + if (fds[1] >= 0) + close(fds[1]); + } + + /* Wait for previous dump thread to complete */ + if (dump_thread) { + pthread_join(dump_thread, NULL); + dump_thread = 0; + } + + return 0; +} + +#endif diff --git a/pcap/Makefile.in b/pcap/Makefile.in new file mode 100644 index 0000000..d469c2b --- /dev/null +++ b/pcap/Makefile.in @@ -0,0 +1,30 @@ +# +include @top_srcdir@/Rules.make + +CFLAGS+=-I@top_srcdir@ -I@top_srcdir@/libipulog/include -I@top_srcdir@/include +SH_CFLAGS:=$(CFLAGS) -fPIC + +# Normally You should not need to change anything below +# + +SHARED_LIBS=ulogd_PCAP.so + +all: $(SHARED_LIBS) + +distrib: + +$(SHARED_LIBS): %.so: %_sh.o + $(LD) -shared -o $@ $< -lc -lpcap + +%_sh.o: %.c + $(CC) $(SH_CFLAGS) -o $@ -c $< + +clean: + $(RM) $(SHARED_LIBS) *.o + +distclean: + $(RM) Makefile + +install: all + $(INSTALL) -m 755 -d $(DESTDIR)$(ULOGD_LIB_PATH) + $(INSTALL) -m 755 *.so $(DESTDIR)$(ULOGD_LIB_PATH) diff --git a/pcap/ulogd_PCAP.c b/pcap/ulogd_PCAP.c new file mode 100644 index 0000000..b22de20 --- /dev/null +++ b/pcap/ulogd_PCAP.c @@ -0,0 +1,286 @@ +/* ulogd_PCAP.c, Version $Revision: 6016 $ + * + * ulogd output target for writing pcap-style files (like tcpdump) + * + * FIXME: descr. + * + * + * (C) 2002 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: ulogd_PCAP.c 6016 2005-09-23 13:37:46Z laforge $ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This is a timeval as stored in disk in a dumpfile. + * It has to use the same types everywhere, independent of the actual + * `struct timeval' + */ + +struct pcap_timeval { + int32_t tv_sec; /* seconds */ + int32_t tv_usec; /* microseconds */ +}; + +/* + * How a `pcap_pkthdr' is actually stored in the dumpfile. + * + * Do not change the format of this structure, in any way (this includes + * changes that only affect the length of fields in this structure), + * and do not make the time stamp anything other than seconds and + * microseconds (e.g., seconds and nanoseconds). Instead: + * + * introduce a new structure for the new format; + * + * send mail to "tcpdump-workers@tcpdump.org", requesting a new + * magic number for your new capture file format, and, when + * you get the new magic number, put it in "savefile.c"; + * + * use that magic number for save files with the changed record + * header; + * + * make the code in "savefile.c" capable of reading files with + * the old record header as well as files with the new record header + * (using the magic number to determine the header format). + * + * Then supply the changes to "patches@tcpdump.org", so that future + * versions of libpcap and programs that use it (such as tcpdump) will + * be able to read your new capture file format. + */ + +struct pcap_sf_pkthdr { + struct pcap_timeval ts; /* time stamp */ + uint32_t caplen; /* length of portion present */ + uint32_t len; /* length this packet (off wire) */ +}; + +#ifndef ULOGD_PCAP_DEFAULT +#define ULOGD_PCAP_DEFAULT "/var/log/ulogd.pcap" +#endif + +#ifndef ULOGD_PCAP_SYNC_DEFAULT +#define ULOGD_PCAP_SYNC_DEFAULT 0 +#endif + +#define NIPQUAD(addr) \ + ((unsigned char *)&addr)[0], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[3] + +static config_entry_t pcapf_ce = { + .key = "file", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_NONE, + .u = { .string = ULOGD_PCAP_DEFAULT } +}; + +static config_entry_t pcapsync_ce = { + .next = &pcapf_ce, + .key = "sync", + .type = CONFIG_TYPE_INT, + .options = CONFIG_OPT_NONE, + .u = { .value = ULOGD_PCAP_SYNC_DEFAULT } +}; + +static FILE *of = NULL; + +struct intr_id { + char* name; + unsigned int id; +}; + +#define INTR_IDS 5 +static struct intr_id intr_ids[INTR_IDS] = { + { "raw.pkt", 0 }, + { "raw.pktlen", 0 }, + { "ip.totlen", 0 }, + { "oob.time.sec", 0 }, + { "oob.time.usec", 0 }, +}; + +#define GET_VALUE(x) ulogd_keyh[intr_ids[x].id].interp->result[ulogd_keyh[intr_ids[x].id].offset].value +#define GET_FLAGS(x) ulogd_keyh[intr_ids[x].id].interp->result[ulogd_keyh[intr_ids[x].id].offset].flags + +static int pcap_output(ulog_iret_t *res) +{ + struct pcap_sf_pkthdr pchdr; + + pchdr.caplen = GET_VALUE(1).ui32; + pchdr.len = GET_VALUE(2).ui32; + + if (GET_FLAGS(3) & ULOGD_RETF_VALID + && GET_FLAGS(4) & ULOGD_RETF_VALID) { + pchdr.ts.tv_sec = GET_VALUE(3).ui32; + pchdr.ts.tv_usec = GET_VALUE(4).ui32; + } else { + /* use current system time */ + struct timeval tv; + gettimeofday(&tv, NULL); + + pchdr.ts.tv_sec = tv.tv_sec; + pchdr.ts.tv_usec = tv.tv_usec; + } + + if (fwrite(&pchdr, sizeof(pchdr), 1, of) != 1) { + ulogd_log(ULOGD_ERROR, "Error during write: %s\n", + strerror(errno)); + return 1; + } + if (fwrite(GET_VALUE(0).ptr, pchdr.caplen, 1, of) != 1) { + ulogd_log(ULOGD_ERROR, "Error during write: %s\n", + strerror(errno)); + return 1; + } + + if (pcapf_ce.u.value) + fflush(of); + + return 0; +} + +/* stolen from libpcap savefile.c */ +#define LINKTYPE_RAW 101 +#define TCPDUMP_MAGIC 0xa1b2c3d4 + +static int write_pcap_header(void) +{ + struct pcap_file_header pcfh; + int ret; + + pcfh.magic = TCPDUMP_MAGIC; + pcfh.version_major = PCAP_VERSION_MAJOR; + pcfh.version_minor = PCAP_VERSION_MINOR; + pcfh.thiszone = timezone; + pcfh.sigfigs = 0; + pcfh.snaplen = 65535; /* we don't know the length in advance */ + pcfh.linktype = LINKTYPE_RAW; + + ret = fwrite(&pcfh, sizeof(pcfh), 1, of); + fflush(of); + + return ret; +} + +/* get all key id's for the keys we are intrested in */ +static int get_ids(void) +{ + int i; + struct intr_id *cur_id; + + for (i = 0; i < INTR_IDS; i++) { + cur_id = &intr_ids[i]; + cur_id->id = keyh_getid(cur_id->name); + if (!cur_id->id) { + ulogd_log(ULOGD_ERROR, + "Cannot resolve keyhash id for %s\n", + cur_id->name); + return 1; + } + } + return 0; +} + +void append_create_outfile(void) { + struct stat st_dummy; + int exist = 0; + + if (stat(pcapf_ce.u.string, &st_dummy) == 0 && st_dummy.st_size > 0) { + exist = 1; + } + + if (!exist) { + of = fopen(pcapf_ce.u.string, "w"); + if (!of) { + ulogd_log(ULOGD_FATAL, "can't open pcap file: %s\n", + strerror(errno)); + exit(2); + } + if (!write_pcap_header()) { + ulogd_log(ULOGD_FATAL, "can't write pcap header: %s\n", + strerror(errno)); + exit(2); + } + } else { + of = fopen(pcapf_ce.u.string, "a"); + if (!of) { + ulogd_log(ULOGD_FATAL, "can't open pcap file: %s\n", + strerror(errno)); + exit(2); + } + } +} + +static void pcap_signal_handler(int signal) +{ + switch (signal) { + case SIGHUP: + ulogd_log(ULOGD_NOTICE, "pcap: reopening capture file\n"); + fclose(of); + append_create_outfile(); + break; + default: + break; + } +} + +static int pcap_init(void) +{ + /* FIXME: error handling */ + config_parse_file("PCAP", &pcapsync_ce); + +#ifdef DEBUG_PCAP + of = stdout; +#else + append_create_outfile(); +#endif + return 0; +} + +static void pcap_fini(void) +{ + if (of) + fclose(of); +} + +static ulog_output_t pcap_op = { + .name = "pcap", + .init = &pcap_init, + .fini = &pcap_fini, + .output = &pcap_output, + .signal = &pcap_signal_handler, +}; + +void _init(void) +{ + if (get_ids()) { + ulogd_log(ULOGD_ERROR, "can't resolve all keyhash id's\n"); + } + + register_output(&pcap_op); +} diff --git a/pgsql/Makefile b/pgsql/Makefile new file mode 100644 index 0000000..316bb9f --- /dev/null +++ b/pgsql/Makefile @@ -0,0 +1,30 @@ +# + +# Normally You should not need to change anything below +# +include ../Rules.make + +CFLAGS+=-I.. -I../libipulog/include -I../include +SH_CFLAGS:=$(CFLAGS) -fPIC + +SHARED_LIBS=ulogd_PGSQL.so + +all: $(SHARED_LIBS) + +distrib: + +$(SHARED_LIBS): %.so: %_sh.o + $(LD) -shared $(PGSQL_LDFLAGS) -o $@ $< -lc + +%_sh.o: %.c + $(CC) $(PGSQL_CFLAGS) $(SH_CFLAGS) -o $@ -c $< + +clean: + $(RM) $(SHARED_LIBS) *.o + +distclean: + $(RM) Makefile + +install: all + $(INSTALL) -m 755 -d $(DESTDIR)$(ULOGD_LIB_PATH) + $(INSTALL) -m 755 *.so $(DESTDIR)$(ULOGD_LIB_PATH) diff --git a/pgsql/Makefile.in b/pgsql/Makefile.in new file mode 100644 index 0000000..a242e0d --- /dev/null +++ b/pgsql/Makefile.in @@ -0,0 +1,30 @@ +# + +# Normally You should not need to change anything below +# +include @top_srcdir@/Rules.make + +CFLAGS+=-I@top_srcdir@ -I@top_srcdir@/libipulog/include -I@top_srcdir@/include +SH_CFLAGS:=$(CFLAGS) -fPIC + +SHARED_LIBS=ulogd_PGSQL.so + +all: $(SHARED_LIBS) + +distrib: + +$(SHARED_LIBS): %.so: %_sh.o + $(LD) -shared $(PGSQL_LDFLAGS) -o $@ $< -lc + +%_sh.o: %.c + $(CC) $(PGSQL_CFLAGS) $(SH_CFLAGS) -o $@ -c $< + +clean: + $(RM) $(SHARED_LIBS) *.o + +distclean: + $(RM) Makefile + +install: all + $(INSTALL) -m 755 -d $(DESTDIR)$(ULOGD_LIB_PATH) + $(INSTALL) -m 755 *.so $(DESTDIR)$(ULOGD_LIB_PATH) diff --git a/pgsql/ulogd_PGSQL.c b/pgsql/ulogd_PGSQL.c new file mode 100644 index 0000000..6b7d811 --- /dev/null +++ b/pgsql/ulogd_PGSQL.c @@ -0,0 +1,464 @@ +/* ulogd_PGSQL.c, Version $Revision: 6404 $ + * + * ulogd output plugin for logging to a PGSQL database + * + * (C) 2000-2005 by Harald Welte + * This software is distributed under the terms of GNU GPL + * + * This plugin is based on the MySQL plugin made by Harald Welte. + * The support PostgreSQL were made by Jakab Laszlo. + * + */ + +#include +#include +#include +#include +#include +#include + + +#ifdef DEBUG_PGSQL +#define DEBUGP(x, args...) fprintf(stderr, x, ## args) +#else +#define DEBUGP(x, args...) +#endif + +struct _field { + char name[ULOGD_MAX_KEYLEN]; + unsigned int id; + struct _field *next; +}; + +/* the database handle we are using */ +static PGconn *dbh; + +/* a linked list of the fields the table has */ +static struct _field *fields; + +/* buffer for our insert statement */ +static char *stmt; + +/* pointer to the beginning of the "VALUES" part */ +static char *stmt_val; + +/* pointer to current inser position in statement */ +static char *stmt_ins; + +/* our configuration directives */ +static config_entry_t db_ce = { + .key = "db", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_MANDATORY, +}; + +static config_entry_t host_ce = { + .next = &db_ce, + .key = "host", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_NONE, +}; + +static config_entry_t user_ce = { + .next = &host_ce, + .key = "user", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_MANDATORY, +}; + +static config_entry_t pass_ce = { + .next = &user_ce, + .key = "pass", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_NONE, +}; + +static config_entry_t table_ce = { + .next = &pass_ce, + .key = "table", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_MANDATORY, +}; + +static config_entry_t schema_ce = { + .next = &table_ce, + .key = "schema", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_NONE, + .u = { .string = "public" }, +}; + +static config_entry_t port_ce = { + .next = &schema_ce, + .key = "port", + .type = CONFIG_TYPE_INT, + .options = CONFIG_OPT_NONE, +}; + +static unsigned char pgsql_have_schemas; + +/* our main output function, called by ulogd */ +static int pgsql_output(ulog_iret_t *result) +{ + struct _field *f; + ulog_iret_t *res; + PGresult *pgres; +#ifdef IP_AS_STRING + char *tmpstr; /* need this for --log-ip-as-string */ + struct in_addr addr; +#endif + + stmt_ins = stmt_val; + + for (f = fields; f; f = f->next) { + res = keyh_getres(f->id); + + if (!res) { + ulogd_log(ULOGD_NOTICE, + "no result for %s ?!?\n", f->name); + } + + if (!res || !IS_VALID((*res))) { + /* no result, we have to fake something */ + sprintf(stmt_ins, "NULL,"); + stmt_ins = stmt + strlen(stmt); + continue; + } + + switch (res->type) { + case ULOGD_RET_INT8: + sprintf(stmt_ins, "%d,", res->value.i8); + break; + case ULOGD_RET_INT16: + sprintf(stmt_ins, "%d,", res->value.i16); + break; + case ULOGD_RET_INT32: + sprintf(stmt_ins, "%d,", res->value.i32); + break; + case ULOGD_RET_INT64: + sprintf(stmt_ins, "%lld,", res->value.i64); + break; + case ULOGD_RET_UINT8: + sprintf(stmt_ins, "%u,", res->value.ui8); + break; + case ULOGD_RET_UINT16: + sprintf(stmt_ins, "%u,", res->value.ui16); + break; + case ULOGD_RET_IPADDR: +#ifdef IP_AS_STRING + *stmt_ins++ = '\''; + memset(&addr, 0, sizeof(addr)); + addr.s_addr = ntohl(res->value.ui32); + tmpstr = (char *)inet_ntoa(addr); + PQescapeString(stmt_ins,tmpstr,strlen(tmpstr)); + stmt_ins = stmt + strlen(stmt); + sprintf(stmt_ins, "',"); + break; +#endif /* IP_AS_STRING */ + /* EVIL: fallthrough when logging IP as + * u_int32_t */ + + case ULOGD_RET_UINT32: + sprintf(stmt_ins, "%u,", res->value.ui32); + break; + case ULOGD_RET_UINT64: + sprintf(stmt_ins, "%llu,", res->value.ui64); + break; + case ULOGD_RET_BOOL: + sprintf(stmt_ins, "'%d',", res->value.b); + break; + case ULOGD_RET_STRING: + *stmt_ins++ = '\''; + PQescapeString(stmt_ins,res->value.ptr,strlen(res->value.ptr)); + stmt_ins = stmt + strlen(stmt); + sprintf(stmt_ins, "',"); + break; + case ULOGD_RET_RAW: + ulogd_log(ULOGD_NOTICE,"%s: pgsql doesn't support type RAW\n",res->key); + sprintf(stmt_ins, "NULL,"); + break; + default: + ulogd_log(ULOGD_NOTICE, + "unknown type %d for %s\n", + res->type, res->key); + break; + } + stmt_ins = stmt + strlen(stmt); + } + *(stmt_ins - 1) = ')'; + DEBUGP("stmt=#%s#\n", stmt); + + /* now we have created our statement, insert it */ + /* Added code by Jaki */ + pgres = PQexec(dbh, stmt); + if(!pgres || PQresultStatus(pgres) != PGRES_COMMAND_OK) { + ulogd_log(ULOGD_ERROR, "sql error during insert: %s\n", + PQresultErrorMessage(pgres)); + return 1; + } + + PQclear(pgres); + + return 0; +} + +#define PGSQL_HAVE_NAMESPACE_TEMPLATE "SELECT nspname FROM pg_namespace n WHERE n.nspname='%s'" + +/* Determine if server support schemas */ +static int pgsql_namespace(void) { + PGresult *result; + char pgbuf[strlen(PGSQL_HAVE_NAMESPACE_TEMPLATE)+strlen(schema_ce.u.string)+1]; + + if (!dbh) + return 1; + + sprintf(pgbuf, PGSQL_HAVE_NAMESPACE_TEMPLATE, schema_ce.u.string); + ulogd_log(ULOGD_DEBUG, "%s\n", pgbuf); + + result = PQexec(dbh, pgbuf); + if (!result) { + ulogd_log(ULOGD_DEBUG, "\n result false"); + return 1; + } + + if (PQresultStatus(result) == PGRES_TUPLES_OK) { + ulogd_log(ULOGD_DEBUG, "using schema %s\n", schema_ce.u.string); + pgsql_have_schemas = 1; + } else { + pgsql_have_schemas = 0; + } + + PQclear(result); + + return 0; +} + +#define PGSQL_INSERTTEMPL "insert into X (Y) values (Z)" +#define PGSQL_VALSIZE 100 + +/* create the static part of our insert statement */ +static int pgsql_createstmt(void) +{ + struct _field *f; + unsigned int size; + char buf[ULOGD_MAX_KEYLEN]; + char *underscore; + + if (stmt) { + ulogd_log(ULOGD_NOTICE, "createstmt called, but stmt" + " already existing\n"); + return 1; + } + + /* caclulate the size for the insert statement */ + size = strlen(PGSQL_INSERTTEMPL) + strlen(table_ce.u.string) + strlen(schema_ce.u.string) + 1; + + for (f = fields; f; f = f->next) { + /* we need space for the key and a comma, as well as + * enough space for the values */ + size += strlen(f->name) + 1 + PGSQL_VALSIZE; + } + + ulogd_log(ULOGD_DEBUG, "allocating %u bytes for statement\n", size); + + stmt = (char *) malloc(size); + + if (!stmt) { + ulogd_log(ULOGD_ERROR, "OOM!\n"); + return 1; + } + + if (pgsql_have_schemas) { + sprintf(stmt, "insert into %s.%s (", schema_ce.u.string, table_ce.u.string); + } else { + sprintf(stmt, "insert into %s (", table_ce.u.string); + } + + stmt_val = stmt + strlen(stmt); + + for (f = fields; f; f = f->next) { + strncpy(buf, f->name, ULOGD_MAX_KEYLEN); + while ((underscore = strchr(buf, '.'))) + *underscore = '_'; + sprintf(stmt_val, "%s,", buf); + stmt_val = stmt + strlen(stmt); + } + *(stmt_val - 1) = ')'; + + sprintf(stmt_val, " values ("); + stmt_val = stmt + strlen(stmt); + + ulogd_log(ULOGD_DEBUG, "stmt='%s'\n", stmt); + + return 0; +} + +#define PGSQL_GETCOLUMN_TEMPLATE "SELECT a.attname FROM pg_class c, pg_attribute a WHERE c.relname ='%s' AND a.attnum>0 AND a.attrelid=c.oid ORDER BY a.attnum" + +#define PGSQL_GETCOLUMN_TEMPLATE_SCHEMA "SELECT a.attname FROM pg_attribute a, pg_class c LEFT JOIN pg_namespace n ON c.relnamespace=n.oid WHERE c.relname ='%s' AND n.nspname='%s' AND a.attnum>0 AND a.attrelid=c.oid AND a.attisdropped=FALSE ORDER BY a.attnum" + +/* find out which columns the table has */ +static int pgsql_get_columns(const char *table) +{ + PGresult *result; + char buf[ULOGD_MAX_KEYLEN]; + char pgbuf[strlen(PGSQL_GETCOLUMN_TEMPLATE_SCHEMA)+strlen(table)+strlen(schema_ce.u.string)+2]; + char *underscore; + struct _field *f; + int id; + int intaux; + + if (!dbh) + return 1; + + if (pgsql_have_schemas) { + snprintf(pgbuf, sizeof(pgbuf)-1, PGSQL_GETCOLUMN_TEMPLATE_SCHEMA, table, schema_ce.u.string); + } else { + snprintf(pgbuf, sizeof(pgbuf)-1, PGSQL_GETCOLUMN_TEMPLATE, table); + } + + ulogd_log(ULOGD_DEBUG, "%s\n", pgbuf); + + result = PQexec(dbh, pgbuf); + if (!result) { + ulogd_log(ULOGD_DEBUG, "\n result false"); + return 1; + } + + if (PQresultStatus(result) != PGRES_TUPLES_OK) { + ulogd_log(ULOGD_DEBUG, "\n pres_command_not_ok"); + return 1; + } + + for (intaux=0; intauxname, buf, ULOGD_MAX_KEYLEN); + f->id = id; + f->next = fields; + fields = f; + } + + PQclear(result); + return 0; +} + +static int exit_nicely(PGconn *conn) +{ + PQfinish(conn); + return 0;; +} + +/* make connection and select database */ +static int pgsql_open_db(char *server, int port, char *user, char *pass, + char *db) +{ + int len; + char *connstr; + + /* 80 is more than what we need for the fixed parts below */ + len = 80 + strlen(user) + strlen(db); + + /* hostname and and password are the only optionals */ + if (server) + len += strlen(server); + if (pass) + len += strlen(pass); + if (port) + len += 20; + + connstr = (char *) malloc(len); + if (!connstr) + return 1; + + if (server) { + strcpy(connstr, " host="); + strcat(connstr, server); + } + + if (port) { + char portbuf[20]; + snprintf(portbuf, sizeof(portbuf), " port=%u", port); + strcat(connstr, portbuf); + } + + strcat(connstr, " dbname="); + strcat(connstr, db); + strcat(connstr, " user="); + strcat(connstr, user); + + if (pass) { + strcat(connstr, " password="); + strcat(connstr, pass); + } + + dbh = PQconnectdb(connstr); + if (PQstatus(dbh)!=CONNECTION_OK) { + exit_nicely(dbh); + return 1; + } + + return 0; +} + +static int pgsql_init(void) +{ + /* have the opts parsed */ + config_parse_file("PGSQL", &port_ce); + + if (pgsql_open_db(host_ce.u.string, port_ce.u.value, user_ce.u.string, + pass_ce.u.string, db_ce.u.string)) { + ulogd_log(ULOGD_ERROR, "can't establish database connection\n"); + return 1; + } + + if (pgsql_namespace()) { + return 1; + ulogd_log(ULOGD_ERROR, "unable to test for pgsql schemas\n"); + } + + /* read the fieldnames to know which values to insert */ + if (pgsql_get_columns(table_ce.u.string)) { + ulogd_log(ULOGD_ERROR, "unable to get pgsql columns\n"); + return 1; + } + pgsql_createstmt(); + + return 0; +} + +static void pgsql_fini(void) +{ + PQfinish(dbh); +} + +static ulog_output_t pgsql_plugin = { + .name = "pgsql", + .output = &pgsql_output, + .init = &pgsql_init, + .fini = &pgsql_fini, +}; + +void _init(void) +{ + register_output(&pgsql_plugin); +} diff --git a/sqlite3/Makefile b/sqlite3/Makefile new file mode 100644 index 0000000..b3085c6 --- /dev/null +++ b/sqlite3/Makefile @@ -0,0 +1,30 @@ +# Generated automatically from Makefile.in by configure. +# +# Normally You should not need to change anything below +# +include ../Rules.make + +CFLAGS+=-I.. -I../libipulog/include -I../include +SH_CFLAGS:=$(CFLAGS) -fPIC + +SHARED_LIBS=ulogd_SQLITE3.so + +all: $(SHARED_LIBS) + +distrib: + +$(SHARED_LIBS): %.so: %_sh.o + $(LD) -shared $(SQLITE3_LDFLAGS) -o $@ $< -lc + +%_sh.o: %.c + $(CC) $(SQLITE3_CFLAGS) $(SH_CFLAGS) -o $@ -c $< + +clean: + $(RM) $(SHARED_LIBS) *.o + +distclean: + $(RM) Makefile + +install: all + $(INSTALL) -m 755 -d $(DESTDIR)$(ULOGD_LIB_PATH) + $(INSTALL) -m 755 *.so $(DESTDIR)$(ULOGD_LIB_PATH) diff --git a/sqlite3/Makefile.in b/sqlite3/Makefile.in new file mode 100644 index 0000000..5c0e1f1 --- /dev/null +++ b/sqlite3/Makefile.in @@ -0,0 +1,29 @@ +# +# Normally You should not need to change anything below +# +include @top_srcdir@/Rules.make + +CFLAGS+=-I@top_srcdir@ -I@top_srcdir@/libipulog/include -I@top_srcdir@/include +SH_CFLAGS:=$(CFLAGS) -fPIC + +SHARED_LIBS=ulogd_SQLITE3.so + +all: $(SHARED_LIBS) + +distrib: + +$(SHARED_LIBS): %.so: %_sh.o + $(LD) -shared $(SQLITE3_LDFLAGS) -o $@ $< -lc + +%_sh.o: %.c + $(CC) $(SQLITE3_CFLAGS) $(SH_CFLAGS) -o $@ -c $< + +clean: + $(RM) $(SHARED_LIBS) *.o + +distclean: + $(RM) Makefile + +install: all + $(INSTALL) -m 755 -d $(DESTDIR)$(ULOGD_LIB_PATH) + $(INSTALL) -m 755 *.so $(DESTDIR)$(ULOGD_LIB_PATH) diff --git a/sqlite3/ulogd_SQLITE3.c b/sqlite3/ulogd_SQLITE3.c new file mode 100644 index 0000000..4c9caeb --- /dev/null +++ b/sqlite3/ulogd_SQLITE3.c @@ -0,0 +1,412 @@ +/* + * ulogd output plugin for logging to a SQLITE database + * + * (C) 2005 by Ben La Monica + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This module has been adapted from the ulogd_MYSQL.c written by + * Harald Welte + * Alex Janssen + * + * You can see benchmarks and an explanation of the testing + * at http://www.pojo.us/ulogd/ + * + * 2005-02-09 Harald Welte : + * - port to ulogd-1.20 + */ + +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG_SQLITE3 +#define DEBUGP(x, args...) fprintf(stderr, x, ## args) +#else +#define DEBUGP(x, args...) +#endif + +struct _field { + char name[ULOGD_MAX_KEYLEN]; + unsigned int id; + struct _field *next; +}; + +/* the database handle we are using */ +static sqlite3 *dbh; + +/* a linked list of the fields the table has */ +static struct _field *fields; + +/* buffer for our insert statement */ +static char *stmt; + +/* pointer to the final prepared statement */ +static sqlite3_stmt *p_stmt; + +/* number of statements to buffer before we commit */ +static int buffer_size; + +/* number of statements currently in the buffer */ +static int buffer_ctr; + +/* our configuration directives */ +static config_entry_t db_ce = { + .key = "db", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_MANDATORY, +}; + +static config_entry_t table_ce = { + .next = &db_ce, + .key = "table", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_MANDATORY, +}; + +static config_entry_t buffer_ce = { + .next = &table_ce, + .key = "buffer", + .type = CONFIG_TYPE_INT, + .options = CONFIG_OPT_MANDATORY, +}; + +/* our main output function, called by ulogd */ +static int _sqlite3_output(ulog_iret_t *result) +{ + struct _field *f; + ulog_iret_t *res; + int col_counter; +#ifdef IP_AS_STRING + char *ipaddr; + struct in_addr addr; +#endif + + col_counter = 1; + for (f = fields; f; f = f->next) { + res = keyh_getres(f->id); + + if (!res) { + ulogd_log(ULOGD_NOTICE, + "no result for %s ?!?\n", f->name); + } + + if (!res || !IS_VALID((*res))) { + /* no result, pass a null */ + sqlite3_bind_null(p_stmt, col_counter); + col_counter++; + continue; + } + + switch (res->type) { + case ULOGD_RET_INT8: + sqlite3_bind_int(p_stmt,col_counter,res->value.i8); + break; + case ULOGD_RET_INT16: + sqlite3_bind_int(p_stmt,col_counter,res->value.i16); + break; + case ULOGD_RET_INT32: + sqlite3_bind_int(p_stmt,col_counter,res->value.i32); + break; + case ULOGD_RET_INT64: + sqlite3_bind_int64(p_stmt,col_counter,res->value.i64); + break; + case ULOGD_RET_UINT8: + sqlite3_bind_int(p_stmt,col_counter,res->value.ui8); + break; + case ULOGD_RET_UINT16: + sqlite3_bind_int(p_stmt,col_counter,res->value.ui16); + break; + case ULOGD_RET_IPADDR: +#ifdef IP_AS_STRING + memset(&addr, 0, sizeof(addr)); + addr.s_addr = ntohl(res->value.ui32); + ipaddr = inet_ntoa(addr); + sqlite3_bind_text(p_stmt,col_counter,ipaddr,strlen(ipaddr),SQLITE_STATIC); + break; +#endif /* IP_AS_STRING */ + /* EVIL: fallthrough when logging IP as u_int32_t */ + case ULOGD_RET_UINT32: + sqlite3_bind_int(p_stmt,col_counter,res->value.ui32); + break; + case ULOGD_RET_UINT64: + sqlite3_bind_int64(p_stmt,col_counter,res->value.ui64); + break; + case ULOGD_RET_BOOL: + sqlite3_bind_int(p_stmt,col_counter,res->value.b); + break; + case ULOGD_RET_STRING: + sqlite3_bind_text(p_stmt,col_counter,res->value.ptr,strlen(res->value.ptr),SQLITE_STATIC); + break; + default: + ulogd_log(ULOGD_NOTICE, + "unknown type %d for %s\n", + res->type, res->key); + break; + } + + col_counter++; + } + + /* now we have created our statement, insert it */ + + if (sqlite3_step(p_stmt) == SQLITE_DONE) { + sqlite3_reset(p_stmt); + buffer_ctr++; + } else { + ulogd_log(ULOGD_ERROR, "sql error during insert: %s\n", + sqlite3_errmsg(dbh)); + return 1; + } + + /* commit all of the inserts to the database, ie flush buffer */ + if (buffer_ctr >= buffer_size) { + if (sqlite3_exec(dbh,"commit",NULL,NULL,NULL) != SQLITE_OK) + ulogd_log(ULOGD_ERROR,"unable to commit records to db."); + + if (sqlite3_exec(dbh,"begin deferred",NULL,NULL,NULL) != SQLITE_OK) + ulogd_log(ULOGD_ERROR,"unable to begin a new transaction."); + + buffer_ctr = 0; + DEBUGP("committing.\n"); + } + + return 0; +} + +#define _SQLITE3_INSERTTEMPL "insert into X (Y) values (Z)" + +/* create the static part of our insert statement */ +static int _sqlite3_createstmt(void) +{ + struct _field *f; + unsigned int size; + char buf[ULOGD_MAX_KEYLEN]; + char *underscore; + char *stmt_pos; + int col_count; + int i; + + if (stmt) { + ulogd_log(ULOGD_NOTICE, "createstmt called, but stmt" + " already existing\n"); + return 1; + } + + /* caclulate the size for the insert statement */ + size = strlen(_SQLITE3_INSERTTEMPL) + strlen(table_ce.u.string); + + DEBUGP("initial size: %u\n", size); + + col_count = 0; + for (f = fields; f; f = f->next) { + /* we need space for the key and a comma, and a ? */ + size += strlen(f->name) + 3; + DEBUGP("size is now %u since adding %s\n",size,f->name); + col_count++; + } + + DEBUGP("there were %d columns\n",col_count); + DEBUGP("after calc name length: %u\n",size); + + ulogd_log(ULOGD_DEBUG, "allocating %u bytes for statement\n", size); + + stmt = (char *) malloc(size); + + if (!stmt) { + ulogd_log(ULOGD_ERROR, "OOM!\n"); + return 1; + } + + sprintf(stmt, "insert into %s (", table_ce.u.string); + stmt_pos = stmt + strlen(stmt); + + for (f = fields; f; f = f->next) { + strncpy(buf, f->name, ULOGD_MAX_KEYLEN); + while ((underscore = strchr(buf, '.'))) + *underscore = '_'; + sprintf(stmt_pos, "%s,", buf); + stmt_pos = stmt + strlen(stmt); + } + + *(stmt_pos - 1) = ')'; + + sprintf(stmt_pos, " values ("); + stmt_pos = stmt + strlen(stmt); + + for (i = 0; i < col_count - 1; i++) { + sprintf(stmt_pos,"?,"); + stmt_pos += 2; + } + + sprintf(stmt_pos, "?)"); + ulogd_log(ULOGD_DEBUG, "stmt='%s'\n", stmt); + + DEBUGP("about to prepare statement.\n"); + + sqlite3_prepare(dbh,stmt,-1,&p_stmt,0); + + DEBUGP("statement prepared.\n"); + + if (!p_stmt) { + ulogd_log(ULOGD_ERROR,"unable to prepare statement"); + return 1; + } + + return 0; +} + + +/* length of "select * from \0" */ +#define SQLITE_SELECT_LEN 15 + +/* find out which columns the table has */ +static int _sqlite3_get_columns(const char *table) +{ + char buf[ULOGD_MAX_KEYLEN]; + char query[SQLITE_SELECT_LEN + CONFIG_VAL_STRING_LEN] = "select * from \0"; + char *underscore; + struct _field *f; + sqlite3_stmt *schema_stmt; + int column; + int result; + int id; + + if (!dbh) + return 1; + + strncat(query,table,LINE_LEN); + + result = sqlite3_prepare(dbh,query,-1,&schema_stmt,0); + + if (result != SQLITE_OK) + return 1; + + for (column = 0; column < sqlite3_column_count(schema_stmt); column++) { + /* replace all underscores with dots */ + strncpy(buf, sqlite3_column_name(schema_stmt,column), ULOGD_MAX_KEYLEN); + while ((underscore = strchr(buf, '_'))) + *underscore = '.'; + + DEBUGP("field '%s' found: ", buf); + + if (!(id = keyh_getid(buf))) { + DEBUGP(" no keyid!\n"); + continue; + } + + DEBUGP("keyid %u\n", id); + + /* prepend it to the linked list */ + f = (struct _field *) malloc(sizeof *f); + if (!f) { + ulogd_log(ULOGD_ERROR, "OOM!\n"); + return 1; + } + strncpy(f->name, buf, ULOGD_MAX_KEYLEN); + f->id = id; + f->next = fields; + fields = f; + } + + sqlite3_finalize(schema_stmt); + return 0; +} + +/** + * make connection and select database + * returns 0 if database failed to open. + */ +static int _sqlite3_open_db(char *db_file) +{ + DEBUGP("opening database.\n"); + return sqlite3_open(db_file,&dbh); +} + +/* give us an opportunity to close the database down properly */ +static void _sqlite3_fini(void) +{ + DEBUGP("cleaning up db connection\n"); + + /* free up our prepared statements so we can close the db */ + if (p_stmt) { + sqlite3_finalize(p_stmt); + DEBUGP("prepared statement finalized\n"); + } + + if (dbh) { + int result; + /* flush the remaining insert statements to the database. */ + result = sqlite3_exec(dbh,"commit",NULL,NULL,NULL); + + if (result != SQLITE_OK) + ulogd_log(ULOGD_ERROR,"unable to commit remaining records to db."); + + sqlite3_close(dbh); + DEBUGP("database file closed\n"); + } +} + +#define _SQLITE3_BUSY_TIMEOUT 300 + +static int _sqlite3_init(void) +{ + /* have the opts parsed */ + config_parse_file("SQLITE3", &buffer_ce); + + if (_sqlite3_open_db(db_ce.u.string)) { + ulogd_log(ULOGD_ERROR, "can't open the database file\n"); + return 1; + } + + /* set the timeout so that we don't automatically fail + * if the table is busy. */ + sqlite3_busy_timeout(dbh, _SQLITE3_BUSY_TIMEOUT); + + /* read the fieldnames to know which values to insert */ + if (_sqlite3_get_columns(table_ce.u.string)) { + ulogd_log(ULOGD_ERROR, "unable to get sqlite columns\n"); + return 1; + } + + /* initialize our buffer size and counter */ + buffer_size = buffer_ce.u.value; + buffer_ctr = 0; + + DEBUGP("Have a buffer size of : %d\n", buffer_size); + + if (sqlite3_exec(dbh,"begin deferred",NULL,NULL,NULL) != SQLITE_OK) + ulogd_log(ULOGD_ERROR,"can't create a new transaction\n"); + + /* create and prepare the actual insert statement */ + _sqlite3_createstmt(); + + return 0; +} + +static ulog_output_t _sqlite3_plugin = { + .name = "sqlite3", + .output = &_sqlite3_output, + .init = &_sqlite3_init, + .fini = &_sqlite3_fini, +}; + +void _init(void) +{ + register_output(&_sqlite3_plugin); +} + diff --git a/ulogd.8 b/ulogd.8 new file mode 100644 index 0000000..7dfb2e9 --- /dev/null +++ b/ulogd.8 @@ -0,0 +1,64 @@ +.\" Hey, EMACS: -*- nroff -*- +.\" First parameter, NAME, should be all caps +.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection +.\" other parameters are allowed: see man(7), man(1) +.TH ULOGD 8 "November 05, 2002" "Linux Netfilter" +.\" Please adjust this date whenever revising the manpage. +.\" +.\" Some roff macros, for reference: +.\" .nh disable hyphenation +.\" .hy enable hyphenation +.\" .ad l left justify +.\" .ad b justify to both left and right margins +.\" .nf disable filling +.\" .fi enable filling +.\" .br insert line break +.\" .sp insert n+1 empty lines +.\" for manpage-specific macros, see man(7) +.SH NAME +ulogd \- netfilter/iptables ULOG daemon +.SH SYNOPSIS +.B ulogd [options] +.SH DESCRIPTION +.B ulogd +connects to the netlink device of the Linux kernel and reads messages +from the netfilter that get queued with the iptables ULOG target. For +this to work you have to compile the ULOG target into your kernel or +load the respective module. +.PP +The received messages can be logged into files or into a mySQL or +PostgreSQL database. +.SH OPTIONS +.TP +.B -d, --daemon +fork ulogd into background (start as daemon) +.TP +.B -c , --configfile +use as configuration file instead of +.I /etc/ulogd.conf +.TP +.B -h, --help +show usage information +.TP +.B -V, --version +show version information and copyright +.SH FILES +.I /etc/ulogd.conf +.br +.I /var/log/ulogd.log +.SH SEE ALSO +There is more documentation about the daemon and the database plugins +(including examples) in the directories +.nf +.br +.I /usr/share/doc/ulogd +.br +.fi +.I /usr/share/doc/ulogd-mysql +and +.nf +.br +.I /usr/share/doc/ulogd-pgsql +.SH AUTHOR +This manual page was written by Joerg Wendland , +for the Debian GNU/Linux system (but may be used by others). diff --git a/ulogd.c b/ulogd.c new file mode 100644 index 0000000..9b998a9 --- /dev/null +++ b/ulogd.c @@ -0,0 +1,825 @@ +/* ulogd, Version $LastChangedRevision: 5373 $ + * + * $Id: ulogd.c 5373 2005-05-04 01:23:16Z laforge $ + * + * userspace logging daemon for the iptables ULOG target + * of the linux 2.4 netfilter subsystem. + * + * (C) 2000-2003 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: ulogd.c 5373 2005-05-04 01:23:16Z laforge $ + * + * Modifications: + * 14 Jun 2001 Martin Josefsson + * - added SIGHUP handler for logfile cycling + * + * 10 Feb 2002 Alessandro Bono + * - added support for non-fork mode + * - added support for logging to stdout + * + * 09 Sep 2003 Magnus Boden + * - added support for more flexible multi-section conffile + * + * 20 Apr 2004 Nicolas Pougetoux + * - added suppurt for seteuid() + */ + +#define ULOGD_VERSION "1.23" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Size of the socket recevive memory. Should be at least the same size as the + * 'nlbufsiz' module loadtime parameter of ipt_ULOG.o + * If you have _big_ in-kernel queues, you may have to increase this number. ( + * --qthreshold 100 * 1500 bytes/packet = 150kB */ +#define ULOGD_RMEM_DEFAULT 131071 + +/* Size of the receive buffer for the netlink socket. Should be at least of + * RMEM_DEFAULT size. */ +#define ULOGD_BUFSIZE_DEFAULT 150000 + +#ifdef DEBUG +#define DEBUGP(format, args...) fprintf(stderr, format, ## args) +#else +#define DEBUGP(format, args...) +#endif + +/* default config parameters, if not changed in configfile */ +#ifndef ULOGD_LOGFILE_DEFAULT +#define ULOGD_LOGFILE_DEFAULT "/var/log/ulogd.log" +#endif +#ifndef ULOGD_NLGROUP_DEFAULT +#define ULOGD_NLGROUP_DEFAULT 32 +#endif + +/* where to look for the config file */ +#ifndef ULOGD_CONFIGFILE +#define ULOGD_CONFIGFILE "/etc/ulogd.conf" +#endif + +/* global variables */ +static struct ipulog_handle *libulog_h; /* our libipulog handle */ +static unsigned char* libulog_buf; /* the receive buffer */ +static FILE *logfile = NULL; /* logfile pointer */ +static char *ulogd_configfile = ULOGD_CONFIGFILE; + +/* linked list for all registered interpreters */ +static ulog_interpreter_t *ulogd_interpreters; + +/* linked list for all registered output targets */ +static ulog_output_t *ulogd_outputs; + +/*********************************************************************** + * INTERPRETER AND KEY HASH FUNCTIONS (new in 0.9) + ***********************************************************************/ + +/* We keep hashtables of interpreters and registered keys. The hash-tables + * are allocated dynamically at program load time. You may control the + * allocation granularity of both hashes (i.e. the amount of hashtable + * entries are allocated at one time) through modification of the constants + * INTERH_ALLOC_GRAN and KEYH_ALLOC_GRAN + */ + +/* allocation granularith */ +#define INTERH_ALLOC_GRAN 5 + +/* hashtable for all registered interpreters */ +static ulog_interpreter_t **ulogd_interh; + +/* current hashtable size */ +static unsigned int ulogd_interh_ids_alloc; + +/* total number of registered ids */ +static unsigned int ulogd_interh_ids; + +/* allocate a new interpreter id and write it into the interpreter struct */ +static unsigned int interh_allocid(ulog_interpreter_t *ip) +{ + unsigned int id; + + id = ++ulogd_interh_ids; + + if (id >= ulogd_interh_ids_alloc) { + if (!ulogd_interh) + ulogd_interh = (ulog_interpreter_t **) + malloc(INTERH_ALLOC_GRAN * + sizeof(ulog_interpreter_t)); + else + ulogd_interh = (ulog_interpreter_t **) + realloc(ulogd_interh, + (INTERH_ALLOC_GRAN + + ulogd_interh_ids_alloc) * + sizeof(ulog_interpreter_t)); + + ulogd_interh_ids_alloc += INTERH_ALLOC_GRAN; + } + + ip->id = id; + ulogd_interh[id] = ip; + return id; +} + +/* get interpreter id by name */ +unsigned int interh_getid(const char *name) +{ + unsigned int i; + for (i = 1; i <= ulogd_interh_ids; i++) + if (!strcmp(name, (ulogd_interh[i])->name)) + return i; + + return 0; +} + +#ifdef DEBUG +/* dump out the contents of the interpreter hash */ +static void interh_dump(void) +{ + unsigned int i; + + for (i = 1; i <= ulogd_interh_ids; i++) + ulogd_log(ULOGD_DEBUG, "ulogd_interh[%d] = %s\n", + i, (ulogd_interh[i])->name); + +} +#endif + +/* key hash allocation granularity */ +#define KEYH_ALLOC_GRAN 20 + +/* hash table for key ids */ +struct ulogd_keyh_entry *ulogd_keyh; + +/* current size of the hashtable */ +static unsigned int ulogd_keyh_ids_alloc; + +/* total number of registered keys */ +static unsigned int ulogd_keyh_ids; + +/* allocate a new key_id */ +static unsigned int keyh_allocid(ulog_interpreter_t *ip, unsigned int offset, + const char *name) +{ + unsigned int id; + + id = ++ulogd_keyh_ids; + + if (id >= ulogd_keyh_ids_alloc) { + if (!ulogd_keyh) { + ulogd_keyh = (struct ulogd_keyh_entry *) + malloc(KEYH_ALLOC_GRAN * + sizeof(struct ulogd_keyh_entry)); + if (!ulogd_keyh) { + ulogd_log(ULOGD_ERROR, "OOM!\n"); + return 0; + } + } else { + ulogd_keyh = (struct ulogd_keyh_entry *) + realloc(ulogd_keyh, (KEYH_ALLOC_GRAN + +ulogd_keyh_ids_alloc) * + sizeof(struct ulogd_keyh_entry)); + + if (!ulogd_keyh) { + ulogd_log(ULOGD_ERROR, "OOM!\n"); + return 0; + } + } + + ulogd_keyh_ids_alloc += KEYH_ALLOC_GRAN; + } + + ulogd_keyh[id].interp = ip; + ulogd_keyh[id].offset = offset; + ulogd_keyh[id].name = name; + + return id; +} + +#ifdef DEBUG +/* dump the keyhash to standard output */ +static void keyh_dump(void) +{ + unsigned int i; + + printf("dumping keyh\n"); + for (i = 1; i <= ulogd_keyh_ids; i++) + printf("ulogd_keyh[%lu] = %s:%u\n", i, + ulogd_keyh[i].interp->name, ulogd_keyh[i].offset); +} +#endif + +/* get keyid by name */ +unsigned int keyh_getid(const char *name) +{ + unsigned int i; + for (i = 1; i <= ulogd_keyh_ids; i++) + if (!strcmp(name, ulogd_keyh[i].name)) + return i; + + return 0; +} + +/* get key name by keyid */ +char *keyh_getname(unsigned int id) +{ + if (id > ulogd_keyh_ids) { + ulogd_log(ULOGD_NOTICE, + "keyh_getname called with invalid id%u\n", id); + return NULL; + } + + return ulogd_keyh[id].interp->name; +} + +/* get result for given key id. does not check if result valid */ +ulog_iret_t *keyh_getres(unsigned int id) +{ + ulog_iret_t *ret; + + if (id > ulogd_keyh_ids) { + ulogd_log(ULOGD_NOTICE, + "keyh_getres called with invalid id %d\n", id); + return NULL; + } + + ret = &ulogd_keyh[id].interp->result[ulogd_keyh[id].offset]; + + return ret; +} + +/*********************************************************************** + * INTERPRETER MANAGEMENT + ***********************************************************************/ + +/* try to lookup a registered interpreter for a given name */ +static ulog_interpreter_t *find_interpreter(const char *name) +{ + unsigned int id; + + id = interh_getid(name); + if (!id) + return NULL; + + return ulogd_interh[id]; +} + +/* the function called by all interpreter plugins for registering their + * target. */ +void register_interpreter(ulog_interpreter_t *me) +{ + unsigned int i; + + /* check if we already have an interpreter with this name */ + if (find_interpreter(me->name)) { + ulogd_log(ULOGD_NOTICE, + "interpreter `%s' already registered\n", me->name); + return; + } + + ulogd_log(ULOGD_INFO, "registering interpreter `%s'\n", me->name); + + /* allocate a new interpreter id for it */ + if (!interh_allocid(me)) { + ulogd_log(ULOGD_ERROR, "unable to obtain interh_id for " + "interpreter '%s'\n", me->name); + return; + } + + /* - allocate one keyh_id for each result of this interpreter + * - link the elements to each other */ + for (i = 0; i < me->key_num; i++) { + if (!keyh_allocid(me, i, me->result[i].key)) { + ulogd_log(ULOGD_ERROR, "unable to obtain keyh_id " + "for interpreter %s, key %d", me->name, + me->result[i].key); + continue; + } + if (i != me->key_num - 1) + me->result[i].next = &me->result[i+1]; + } + + /* all work done, we can prepend the new interpreter to the list */ + if (ulogd_interpreters) + me->result[me->key_num - 1].next = + &ulogd_interpreters->result[0]; + me->next = ulogd_interpreters; + ulogd_interpreters = me; +} + +/*********************************************************************** + * OUTPUT MANAGEMENT + ***********************************************************************/ + +/* try to lookup a registered output plugin for a given name */ +static ulog_output_t *find_output(const char *name) +{ + ulog_output_t *ptr; + + for (ptr = ulogd_outputs; ptr; ptr = ptr->next) { + if (strcmp(name, ptr->name) == 0) + return ptr; + } + + return NULL; +} + +/* the function called by all output plugins for registering themselves */ +void register_output(ulog_output_t *me) +{ + if (find_output(me->name)) { + ulogd_log(ULOGD_NOTICE, "output `%s' already registered\n", + me->name); + exit(EXIT_FAILURE); + } + ulogd_log(ULOGD_INFO, "registering output `%s'\n", me->name); + me->next = ulogd_outputs; + ulogd_outputs = me; +} + +/*********************************************************************** + * MAIN PROGRAM + ***********************************************************************/ + +static FILE syslog_dummy; + +static inline int ulogd2syslog_level(int level) +{ + int syslog_level = LOG_WARNING; + + switch (level) { + case ULOGD_DEBUG: + syslog_level = LOG_DEBUG; + break; + case ULOGD_INFO: + syslog_level = LOG_INFO; + break; + case ULOGD_NOTICE: + syslog_level = LOG_NOTICE; + break; + case ULOGD_ERROR: + syslog_level = LOG_ERR; + break; + case ULOGD_FATAL: + syslog_level = LOG_CRIT; + break; + } + return syslog_level; +} +/* propagate results to all registered output plugins */ +static void propagate_results(ulog_iret_t *ret) +{ + ulog_output_t *p; + + for (p = ulogd_outputs; p; p = p->next) { + (*p->output)(ret); + } +} + +/* clean results (set all values to 0 and free pointers) */ +static void clean_results(ulog_iret_t *ret) +{ + ulog_iret_t *r; + + for (r = ret; r; r = r->next) { + if (r->flags & ULOGD_RETF_FREE) { + free(r->value.ptr); + r->value.ptr = NULL; + } + memset(&r->value, 0, sizeof(r->value)); + r->flags &= ~ULOGD_RETF_VALID; + } +} + +/* call all registered interpreters and hand the results over to + * propagate_results */ +static void handle_packet(ulog_packet_msg_t *pkt) +{ + ulog_iret_t *ret; + ulog_iret_t *allret = NULL; + ulog_interpreter_t *ip; + + unsigned int i,j; + + /* If there are no interpreters registered yet, + * ignore this packet */ + if (!ulogd_interh_ids) { + ulogd_log(ULOGD_NOTICE, + "packet received, but no interpreters found\n"); + return; + } + + for (i = 1; i <= ulogd_interh_ids; i++) { + ip = ulogd_interh[i]; + /* call interpreter */ + if ((ret = ((ip)->interp)(ip, pkt))) { + /* create references for result linked-list */ + for (j = 0; j < ip->key_num; j++) { + if (IS_VALID(ip->result[j])) { + ip->result[j].cur_next = allret; + allret = &ip->result[j]; + } + } + } + } + propagate_results(allret); + clean_results(ulogd_interpreters->result); +} + +/* plugin loader to dlopen() a plugins */ +static int load_plugin(char *file) +{ + if (!dlopen(file, RTLD_NOW)) { + ulogd_log(ULOGD_ERROR, "load_plugins: '%s': %s\n", file, + dlerror()); + return 1; + } + return 0; +} + +/* open the logfile */ +static int logfile_open(const char *name) +{ + if (!strcmp(name, "syslog")) { + openlog("ulogd", LOG_PID, LOG_DAEMON); + logfile = &syslog_dummy; + } else if (!strcmp(name,"stdout")) + logfile = stdout; + else { + logfile = fopen(name, "a"); + if (!logfile) { + fprintf(stderr, "ERROR: can't open logfile %s: %s\n", + name, strerror(errno)); + exit(2); + } + } + ulogd_log(ULOGD_INFO, "ulogd Version %s starting\n", ULOGD_VERSION); + return 0; +} + +/* wrapper to handle conffile error codes */ +static int parse_conffile(const char *section, config_entry_t *ce) +{ + int err; + + err = config_parse_file(section, ce); + + switch(err) { + case 0: + return 0; + break; + case -ERROPEN: + ulogd_log(ULOGD_ERROR, + "unable to open configfile: %s\n", + ulogd_configfile); + break; + case -ERRMAND: + ulogd_log(ULOGD_ERROR, + "mandatory option \"%s\" not found\n", + config_errce->key); + break; + case -ERRMULT: + ulogd_log(ULOGD_ERROR, + "option \"%s\" occurred more than once\n", + config_errce->key); + break; + case -ERRUNKN: + ulogd_log(ULOGD_ERROR, + "unknown config key \"%s\"\n", + config_errce->key); + break; + case -ERRSECTION: + ulogd_log(ULOGD_ERROR, + "section \"%s\" not found\n", section); + break; + } + return 1; + +} + +/* configuration directives of the main program */ +static config_entry_t logf_ce = { NULL, "logfile", CONFIG_TYPE_STRING, + CONFIG_OPT_NONE, 0, + { string: ULOGD_LOGFILE_DEFAULT } }; + +static config_entry_t bufsiz_ce = { &logf_ce, "bufsize", CONFIG_TYPE_INT, + CONFIG_OPT_NONE, 0, + { value: ULOGD_BUFSIZE_DEFAULT } }; + +static config_entry_t plugin_ce = { &bufsiz_ce, "plugin", CONFIG_TYPE_CALLBACK, + CONFIG_OPT_MULTI, 0, + { parser: &load_plugin } }; + +static config_entry_t nlgroup_ce = { &plugin_ce, "nlgroup", CONFIG_TYPE_INT, + CONFIG_OPT_NONE, 0, + { value: ULOGD_NLGROUP_DEFAULT } }; + +static config_entry_t loglevel_ce = { &nlgroup_ce, "loglevel", CONFIG_TYPE_INT, + CONFIG_OPT_NONE, 0, + { value: ULOGD_NOTICE } }; +static config_entry_t rmem_ce = { &loglevel_ce, "rmem", CONFIG_TYPE_INT, + CONFIG_OPT_NONE, 0, + { value: ULOGD_RMEM_DEFAULT } }; + +/* log message to the logfile */ +void __ulogd_log(int level, char *file, int line, const char *format, ...) +{ + char *timestr; + va_list ap; + time_t tm; + FILE *outfd; + + /* log only messages which have level at least as high as loglevel */ + if (level < loglevel_ce.u.value) + return; + + if (logfile == &syslog_dummy) { + /* FIXME: this omit's the 'file' string */ + va_start(ap, format); + vsyslog(ulogd2syslog_level(level), format, ap); + va_end(ap); + } else { + if (logfile) + outfd = logfile; + else + outfd = stderr; + + va_start(ap, format); + + tm = time(NULL); + timestr = ctime(&tm); + timestr[strlen(timestr)-1] = '\0'; + fprintf(outfd, "%s <%1.1d> %s:%d ", timestr, level, file, line); + + vfprintf(outfd, format, ap); + va_end(ap); + + /* flush glibc's buffer */ + fflush(outfd); + } +} + +static void sigterm_handler(int signal) +{ + ulog_output_t *p; + + ulogd_log(ULOGD_NOTICE, "sigterm received, exiting\n"); + + ipulog_destroy_handle(libulog_h); + free(libulog_buf); + if (logfile != stdout && logfile != &syslog_dummy) + fclose(logfile); + + for (p = ulogd_outputs; p; p = p->next) { + if (p->fini) + (*p->fini)(); + } + + exit(0); +} + +static void sighup_handler(int signal) +{ + ulog_output_t *p; + + if (logfile != stdout && logfile != &syslog_dummy) { + fclose(logfile); + logfile = fopen(logf_ce.u.string, "a"); + if (!logfile) + sigterm_handler(signal); + } + + ulogd_log(ULOGD_NOTICE, "sighup received, calling plugin handlers\n"); + + for (p = ulogd_outputs; p; p = p->next) { + if (p->signal) + (*p->signal)(SIGHUP); + } +} + +static void print_usage(void) +{ + /* FIXME */ + printf("ulogd Version %s\n", ULOGD_VERSION); + printf("Copyright (C) 2000-2005 Harald Welte " + "\n"); + printf("This is free software with ABSOLUTELY NO WARRANTY.\n\n"); + printf("Parameters:\n"); + printf("\t-h --help\tThis help page\n"); + printf("\t-V --version\tPrint version information\n"); + printf("\t-d --daemon\tDaemonize (fork into background)\n"); + printf("\t-c --configfile\tUse alternative Configfile\n"); + printf("\t-u --uid\tChange UID/GID\n"); +} + +static struct option opts[] = { + { "version", 0, NULL, 'V' }, + { "daemon", 0, NULL, 'd' }, + { "help", 0, NULL, 'h' }, + { "configfile", 1, NULL, 'c'}, + { "uid", 1, NULL, 'u' }, + { 0 } +}; + +int main(int argc, char* argv[]) +{ + int len; + int argch; + int daemonize = 0; + int change_uid = 0; + char *user = NULL; + struct passwd *pw; + uid_t uid = 0; + gid_t gid = 0; + ulog_packet_msg_t *upkt; + ulog_output_t *p; + + + while ((argch = getopt_long(argc, argv, "c:dh::Vu:", opts, NULL)) != -1) { + switch (argch) { + default: + case '?': + if (isprint(optopt)) + fprintf(stderr, "Unknown option `-%c'.\n", optopt); + else + fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt); + + print_usage(); + exit(1); + break; + case 'h': + print_usage(); + exit(0); + break; + case 'd': + daemonize = 1; + break; + case 'V': + printf("ulogd Version %s\n", ULOGD_VERSION); + printf("Copyright (C) 2000-2005 Harald Welte " + "\n"); + exit(0); + break; + case 'c': + ulogd_configfile = optarg; + break; + case 'u': + change_uid = 1; + user = strdup(optarg); + pw = getpwnam(user); + if (!pw) { + printf("Unknown user %s.\n", user); + free(user); + exit(1); + } + uid = pw->pw_uid; + gid = pw->pw_gid; + break; + } + } + + if (config_register_file(ulogd_configfile)) { + ulogd_log(ULOGD_FATAL, "error registering configfile \"%s\"\n", + ulogd_configfile); + exit(1); + } + + /* parse config file */ + if (parse_conffile("global", &rmem_ce)) { + ulogd_log(ULOGD_FATAL, "parse_conffile\n"); + exit(1); + } + + /* allocate a receive buffer */ + libulog_buf = (unsigned char *) malloc(bufsiz_ce.u.value); + + if (!libulog_buf) { + ulogd_log(ULOGD_FATAL, "unable to allocate receive buffer" + "of %d bytes\n", bufsiz_ce.u.value); + ipulog_perror(NULL); + exit(1); + } + + /* create ipulog handle */ + libulog_h = ipulog_create_handle(ipulog_group2gmask(nlgroup_ce.u.value), + rmem_ce.u.value); + + if (!libulog_h) { + /* if some error occurrs, print it to stderr */ + ulogd_log(ULOGD_FATAL, "unable to create ipulogd handle\n"); + ipulog_perror(NULL); + exit(1); + } + + + if (change_uid) { + ulogd_log(ULOGD_NOTICE, "Changing UID / GID\n"); + if (setgid(gid)) { + ulogd_log(ULOGD_FATAL, "can't set GID\n"); + ipulog_perror(NULL); + exit(1); + } + if (setegid(gid)) { + ulogd_log(ULOGD_FATAL, "can't sett effective GID\n"); + ipulog_perror(NULL); + exit(1); + } + if (initgroups(user, gid)) { + ulogd_log(ULOGD_FATAL, "can't set user secondary GID\n"); + ipulog_perror(NULL); + exit(1); + } + if (setuid(uid)) { + ulogd_log(ULOGD_FATAL, "can't set UID\n"); + ipulog_perror(NULL); + exit(1); + } + if (seteuid(uid)) { + ulogd_log(ULOGD_FATAL, "can't set effective UID\n"); + ipulog_perror(NULL); + exit(1); + } + } + + logfile_open(logf_ce.u.string); + + for (p = ulogd_outputs; p; p = p->next) { + if (p->init) + (*p->init)(); + } + +#ifdef DEBUG + /* dump key and interpreter hash */ + interh_dump(); + keyh_dump(); +#endif + if (daemonize){ + if (fork()) { + exit(0); + } + if (logfile != stdout) + fclose(stdout); + fclose(stderr); + fclose(stdin); + setsid(); + } + + /* send SIGINT to the term handler, since they hit CTRL-C */ + signal(SIGINT, &sigterm_handler); + signal(SIGHUP, &sighup_handler); + signal(SIGTERM, &sigterm_handler); + + ulogd_log(ULOGD_INFO, + "initialization finished, entering main loop\n"); + + /* endless loop receiving packets and handling them over to + * handle_packet */ + while ((len = ipulog_read(libulog_h, libulog_buf, + bufsiz_ce.u.value, 1))) { + + if (len <= 0) { + /* this is not supposed to happen */ + ulogd_log(ULOGD_ERROR, "ipulog_read == %d! " + "ipulog_errno == %d, errno = %d\n", + len, ipulog_errno, errno); + } else { + while ((upkt = ipulog_get_packet(libulog_h, + libulog_buf, len))) { + DEBUGP("==> packet received\n"); + handle_packet(upkt); + } + } + } + + /* hackish, but result is the same */ + sigterm_handler(SIGTERM); + return(0); +} diff --git a/ulogd.conf.in b/ulogd.conf.in new file mode 100644 index 0000000..f7bce51 --- /dev/null +++ b/ulogd.conf.in @@ -0,0 +1,125 @@ +# Example configuration for ulogd +# $Id: ulogd.conf.in 5267 2005-02-19 21:33:43Z laforge $ +# + +[global] +###################################################################### +# GLOBAL OPTIONS +###################################################################### + +# netlink multicast group (the same as the iptables --ulog-nlgroup param) +nlgroup=1 + +# logfile for status messages +logfile="/var/log/ulogd.log" + +# loglevel: debug(1), info(3), notice(5), error(7) or fatal(8) +loglevel=5 + +# socket receive buffer size (should be at least the size of the +# in-kernel buffer (ipt_ULOG.o 'nlbufsiz' parameter) +rmem=131071 + +# libipulog/ulogd receive buffer size, should be > rmem +bufsize=150000 + +###################################################################### +# PLUGIN OPTIONS +###################################################################### + +# We have to configure and load all the plugins we want to use + +# general rules: +# 1. load the plugins _first_ from the global section +# 2. options for each plugin in seperate section below + + +# +# ulogd_BASE.so - interpreter plugin for basic IPv4 header fields +# you will always need this +plugin="@libdir@/ulogd_BASE.so" + + +# load the plugin (remove the '#'if you want to enable it +#plugin="@libdir@/ulogd_NETFLOW.so" + +# output plugins. +#plugin="@libdir@/ulogd_LOGEMU.so" +#plugin="@libdir@/ulogd_OPRINT.so" +#plugin="@libdir@/ulogd_MYSQL.so" +#plugin="@libdir@/ulogd_PGSQL.so" +#plugin="@libdir@/ulogd_SQLITE3.so" +#plugin="@libdir@/ulogd_PCAP.so" + +plugin="@libdir@/ulogd_DRL.so" +[DRL] +# nodelimit is the administrative limit for the node +# It will never go above this rate, even if capacity is +# available. A value of 0 means unlimited. +nodelimit=0 + +# Leave this at FPS right now... +policy=FPS + +# Smallest interval at which identities are processed. +estintms=500 + +# Log file location. +drl_logfile="/var/log/drl.log" + +# The verbosity of the DRL logfile. 1 = most verbose, +# 3 = errors only. +drl_loglevel 2 + +# Location of the DRL xml configuration file. +drl_configfile="/etc/drl.xml" + + +[NETFLOW] +# PlanetLab NetFlow logging +# dump interval in minutes +interval=5 + +# CSV dump +csv="/var/www/html/flows.csv" + +# database information +#mysqlpass changeme +#mysqluser="netflow" +#mysqldb="netflow" +#mysqlhost localhost + +# slice map +slicemap="/etc/passwd" + +[LOGEMU] +file="/var/log/ulogd/ulogd.syslogemu" +sync=1 + +[OPRINT] +file="/var/log/ulogd/ulogd.pktlog" + +[MYSQL] +table="ulog" +pass="changeme" +user="laforge" +db="ulogd" +host="localhost" + +[PGSQL] +table="ulog" +schema="public" +pass="changeme" +user="postgres" +db="ulogd" +host="localhost" + +[SQLITE3] +table="ulog" +db="/path/to/sqlite/db" +buffer=200 + +[PCAP] +file="/var/log/ulogd/ulogd.pcap" +sync=1 + diff --git a/ulogd.init b/ulogd.init new file mode 100755 index 0000000..938bb28 --- /dev/null +++ b/ulogd.init @@ -0,0 +1,62 @@ +#!/bin/sh +# +# chkconfig: 345 81 19 +# description: ulogd is the userspace logging daemon for netfilter/iptables +# + + +. /etc/rc.d/init.d/functions + + +function start() +{ + printf "Starting %s: " "ulogd" + daemon /usr/sbin/ulogd -d + echo + touch /var/lock/subsys/ulogd +} + + +function stop() +{ + printf "Stopping %s: " "ulogd" + killproc ulogd + echo + rm -f /var/lock/subsys/ulogd +} + + +function reload() +{ + pid=`pidof ulogd` + if [ "x$pid" != "x" ]; then + kill -HUP $pid 2>/dev/null + fi + touch /var/lock/subsys/ulogd +} + + +case "$1" in + start) + start + ;; + stop) + stop + ;; + restart) + stop + start + ;; + reload) + reload + ;; + status) + status ulogd + exit $? + ;; + *) + printf "Usage: %s {start|stop|status|restart|reload}\n" "ulogd" + exit 1 +esac + +exit 0 diff --git a/ulogd.logrotate b/ulogd.logrotate new file mode 100644 index 0000000..b3fb6d1 --- /dev/null +++ b/ulogd.logrotate @@ -0,0 +1,7 @@ +/var/log/ulogd.log /var/log/ulogd.syslogemu /var/log/ulogd.pktlog /var/log/ulogd.pcap { + missingok + sharedscripts + postrotate + /bin/killall -HUP ulogd 2> /dev/null || true + endscript +} diff --git a/ulogd.spec b/ulogd.spec new file mode 100644 index 0000000..7ab2204 --- /dev/null +++ b/ulogd.spec @@ -0,0 +1,179 @@ +# +# $Id$ +# +%define url $URL$ + +%define name ulogd +%define version 1.24 +%define taglevel 4 + +%define release %{taglevel}%{?pldistro:.%{pldistro}}%{?date:.%{date}} + +Vendor: PlanetLab +Packager: PlanetLab Central +Distribution: PlanetLab %{plrelease} +URL: %(echo %{url} | cut -d ' ' -f 2) + +Summary: ulogd - The userspace logging daemon for netfilter +Name: %{name} +Version: %{version} +Release: %{release} +License: GPL +Group: Network +Source: ftp://ftp.netfilter.org/pub/ulogd/%{name}-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-root +# prep stage will install the appropriate *-devel packages we require --mef +#BuildRequires: kernel-devel mysql-devel libpcap-devel + +#%package mysql +#Summary: MySQL output plugin for ulogd +#Group: Network + +#%package sqlite3 +#Summary: SQLITE3 output plugin for ulogd +#Group: Network + +%package pcap +Summary: PCAP output plugin for ulogd +Group: Network + + +%description +ulogd is an universal logging daemon for the ULOG target of netfilter, the +Linux 2.4 firewalling subsystem. ulogd is able to log packets in variuos +formats to different targets (text files, databases, etc..). It has an +easy-to-use plugin interface to add new protocols and new output targets. + +#%description mysql +#ulogd-mysql is a MySQL output plugin for ulogd. It enables logging of +#firewall information into a MySQL database. + +%description pcap +ulogd-pcap is a LibPCap output plugin for ulogd. It enables logging of +packets to pcap-style files (like tcpdump). + +#%description sqlite3 +#ulogd-sqlite3 is a SQLITE3 output plugin for ulogd. It enables logging of +#firewall information into a SQLITE3 database. + +%prep +%setup +aclocal +autoconf +# bootstrap to avoid BuildRequires of kernel-source, proper-devel, and proper-libs, and mysql-devel +shopt -s nullglob + +%define KERNEL %(rpm -q --qf '%%{VERSION}-%%{RELEASE}-%%{ARCH}\\n' kernel-devel | tail -n 1 ) +count=$(rpm -q kernel-devel| wc -l) +if [ $count -gt 1 ] ; then + echo "WARNING: choosing kernel-devel-$KERNEL" + echo " but there are other kernel-devel packages installed: $(rpm -q kernel-devel)" +fi + +WITH_KERNEL="--with-kernel=/usr/src/kernels/%{KERNEL}" + +#%configure --with-mysql --with-proper $WITH_KERNEL +%configure --with-proper $WITH_KERNEL + +%build +make + +%install +rm -rf %{buildroot} +mkdir -p %{buildroot}/%{_sysconfdir} +mkdir -p %{buildroot}/%{_libdir}/ulogd +mkdir -p %{buildroot}/%{_sbindir}/sbin +mkdir -p %{buildroot}/%{_mandir}/man8 +make DESTDIR=%{buildroot} install + +mkdir -p %{buildroot}/%{_sysconfdir}/rc.d/init.d +install ulogd.init %{buildroot}/%{_sysconfdir}/rc.d/init.d/ulogd +install ulogd.8 %{buildroot}/%{_mandir}/man8/ulogd.8 +install -D -m 644 ulogd.logrotate %{buildroot}/%{_sysconfdir}/logrotate.d/ulogd + +%clean +rm -rf %{buildroot} + +%files +%defattr(0644,root,root,0755) +%attr(0755,root,root) %{_sbindir}/ulogd +#%attr(0755,root,root) %{_bindir}/netflow-import +%{_sysconfdir}/ulogd.conf +%{_sysconfdir}/logrotate.d/ulogd +%attr(0755,root,root) %{_sysconfdir}/rc.d/init.d/ulogd +%{_mandir}/man8/* +%dir %{_libdir}/ulogd +%{_libdir}/ulogd/ulogd_BASE.so +%{_libdir}/ulogd/ulogd_LOCAL.so +%{_libdir}/ulogd/ulogd_LOGEMU.so +#%{_libdir}/ulogd/ulogd_NETFLOW.so +%{_libdir}/ulogd/ulogd_OPRINT.so +%{_libdir}/ulogd/ulogd_PWSNIFF.so +%{_libdir}/ulogd/ulogd_SYSLOG.so +%{_libdir}/ulogd/ulogd_DRL.so +%doc COPYING AUTHORS README +%doc doc/ulogd.txt doc/ulogd.a4.ps doc/ulogd.html + +#%files mysql +#%defattr(0644,root,root,0755) +#%{_libdir}/ulogd/ulogd_MYSQL.so + +#%files pcap +#%defattr(0644,root,root,0755) +#%{_libdir}/ulogd/ulogd_PCAP.so + +#%files sqlite3 +#%defattr(0644,root,root,0755) +#%{_libdir}/ulogd/ulogd_SQLITE3.so + +%changelog +* Wed Dec 5 2007 Marc E. Fiuczynski 1.22-1gm.planetlab ++ ulogd-1.24-3 +- Do not include postgres & sqlite +- update to f7 version + +* Tue Dec 4 2007 Marc E. Fiuczynski 1.22-1gm.planetlab ++ ulogd-1.22-1gm +- updated to 1.21 release +- integrated with planetlab build environment + +* Wed Feb 16 2005 Harald Welte ++ ulogd-1.21-1gm +- updated to 1.21 release +- separate sqlite3 and pcap sub-pacakges + +* Sat Feb 12 2005 Harald Welte ++ ulogd-1.20-1gm +- updated to 1.20 release +- add ulogd.8 manpage + +* Fri Nov 05 2004 Mark Huang 1.02-3.planetlab ++ planetlab-3_0-rc2 +- service ulogd status: exit with appropriate error code + +* Sat Aug 25 2003 Harald Welte ++ ulogd-1.00-1gm +- updated to 1.01 release +- add ulogd.8 manpage + +* Wed Mar 05 2003 Harald Welte ++ ulogd-1.00-1gm +- updated to 1.00 release + +* Mon Sep 24 2001 Harald Welte ++ ulogd-0.97-1cl +- updatd to 0.97 release (to fix endless-one-packet-loop bug) + +* Sun Jun 17 2001 Harald Welte ++ ulogd-0.96-2cl +- updated to 0.96 final release +- use ulogd.init from within source tgz + +* Sun May 20 2001 Harald Welte ++ ulogd-0.96-1cl +- Initial conectiva package +- cleaned up SPEC file +- created mysql subpackage + +* Sun Nov 19 2000 Harald Welte +- Initial RPM package for ulogd-0.9. -- 2.43.0