--- /dev/null
+Harald Welte <laforge@gnumonks.org>
--- /dev/null
+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.
+\f
+ 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.)
+\f
+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.
+\f
+ 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.
+\f
+ 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
+\f
+ 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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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.
+
+ <signature of Ty Coon>, 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.
--- /dev/null
+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
%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/*
--- /dev/null
+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 $@
--- /dev/null
+
+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 <laforge@gnumonks.org>
+
+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.
--- /dev/null
+#
+
+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@
+
--- /dev/null
+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?
--- /dev/null
+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])
+
--- /dev/null
+#include <unistd.h>
+#include <stdio.h>
+#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);
+}
--- /dev/null
+zeile zeile1
+spalte 0815
+asdfasf
--- /dev/null
+#
+
+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
--- /dev/null
+/* config file parser functions
+ *
+ * (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ *
+ * $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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#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;
+}
+
--- /dev/null
+#! /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 <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>. 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 <config-patches@gnu.org>."
+
+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 <stdio.h> /* 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 <sys/systemcfg.h>
+
+ 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 <stdlib.h>
+ #include <unistd.h>
+
+ 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 <unistd.h>
+ 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 <features.h>
+ #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 <features.h>
+ #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' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/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 <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit 0 ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # 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 <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#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 <sys/param.h>
+ 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 <sys/param.h>
+# 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 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> 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:
--- /dev/null
+#! /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 <config-patches@gnu.org>. 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 <config-patches@gnu.org>."
+
+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:
--- /dev/null
+#! /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 <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#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=<directory> proper installed in <directory>
+--with-mysql=<directory> mysql installed in <directoty>
+--with-mysql-log-ip-as-string log IPs as string rather than as
+ unsigned long-integer.
+
+--with-pgsql=<directory> pgsql installed in <directoty>
+--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<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have
+ headers in a nonstandard directory <include dir>
+ 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 </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&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 <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* 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 <stdlib.h>
+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 <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> 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 <limits.h>
+#else
+# include <assert.h>
+#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 <ac_nonexistent.h>
+_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 <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> 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 <limits.h>
+#else
+# include <assert.h>
+#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 <ac_nonexistent.h>
+_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 <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.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_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 <string.h>
+
+_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 <stdlib.h>
+
+_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 <ctype.h>
+#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 <pcap.h>
+_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 <pcap.h>
+_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 <sys/types.h>
+#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 <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.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_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 <string.h>
+
+_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 <stdlib.h>
+
+_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 <ctype.h>
+#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 <sys/types.h>
+#include <time.h>
+
+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 <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> 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 <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#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 <limits.h> declares _doprnt.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define _doprnt innocuous__doprnt
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char _doprnt (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#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 <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> 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 <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#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 <linux/version.h>" | 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 <prop.h>
+_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 <prop.h>
+_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 <pthread.h>
+_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 <pthread.h>
+_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 <bug-autoconf@gnu.org>."
+_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
+
--- /dev/null
+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 <linux/version.h>" | 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=<directory> proper installed in <directory>,
+ [ 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=<directory> mysql installed in <directory>,[
+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=<directory> pgsql installed in <directory>,[
+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=<directory> sqlite3 installed in <directory>,[
+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)
--- /dev/null
+#! /usr/bin/make
+# this file is shamelessly stolen from the iptables CVS tree
+
+LANG_DIRS:=
+
+HOWTOS:=$(wildcard *.sgml)
+HOWTOS+=$(foreach dir, $(LANG_DIRS), $(wildcard $(dir)/*.sgml))
+
+TXT_HOWTOS:=$(HOWTOS:.sgml=.txt)
+HTML_HOWTOS:=$(HOWTOS:.sgml=.html)
+PSA4_HOWTOS:=$(HOWTOS:.sgml=.a4.ps)
+PSUS_HOWTOS:=$(HOWTOS:.sgml=.letter.ps)
+
+HOWTO_FLAGS_it/=-c latin -l it
+HOWTO_FLAGS_fr/=-c latin -l fr
+
+user_calls_make:
+
+distrib: $(TXT_HOWTOS) $(PSA4_HOWTOS) $(HTML_HOWTOS)
+
+HOWTOs: $(TXT_HOWTOS) $(HTML_HOWTOS) $(PSA4_HOWTOS) $(PSUS_HOWTOS)
+
+# Remake all if Makefile changes.
+$(TXT_HOWTOS) $(HTML_HOWTOS) $(PSA4_HOWTOS) $(PSUS_HOWTOS): Makefile
+
+# Stupid sgml2* tools strip dirnames for output files. 8(
+%.txt: %.sgml
+ @echo Making $@: && cd `dirname $<` && sgml2txt --filter $(HOWTO_FLAGS_$(dir $<)) `basename $<` 2>&1 | sed "s?^<standard input>:\([0-9]*\):[^ ]* ?$<:\1:?"
+
+%.a4.dvi: %.sgml
+ @echo Making $@: && cd `dirname $<` && sgml2latex --papersize=a4 --output=dvi $(HOWTO_FLAGS_$(dir $<)) `basename $<` 2>&1 | sed "s?^<standard input>:\([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?^<standard input>:\([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?^<standard input>:\([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:
--- /dev/null
+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)
+ );
+
+
--- /dev/null
+# 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)
+);
+
--- /dev/null
+/* 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)
+);
+
+
--- /dev/null
+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
+ );
+
+
--- /dev/null
+%!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
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.21">
+ <TITLE>ULOGD - the Userspace Logging Daemon</TITLE>
+</HEAD>
+<BODY>
+<H1>ULOGD - the Userspace Logging Daemon</H1>
+
+<H2>Harald Welte <laforge@gnumonks.org></H2>Revision $Revision: 5846 $, $Date: 2005-07-12 17:33:23 +0200 (Tue, 12 Jul 2005) $
+<HR>
+<EM>This is the documentation for <CODE>ulogd</CODE>, the Userspace logging daemon.
+ulogd makes use of the Linux >= 2.4.x packet filter subsystem (iptables) and
+the ULOG target for iptables.</EM>
+<HR>
+<H2><A NAME="s1">1. DESIGN</A></H2>
+
+<H2><A NAME="ss1.1">1.1 CONCEPT</A>
+</H2>
+
+<P>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:</P>
+<P>
+<DL>
+<DT><B>Interpreter plugins</B><DD><P>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.</P>
+
+<DT><B>Output plugins</B><DD><P>... 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.</P>
+
+</DL>
+</P>
+
+<H2><A NAME="ss1.2">1.2 DETAILS</A>
+</H2>
+
+<P>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.</P>
+<P>Rusty advised me to use some kind of type-key-value triples, which is in fact
+what I implemented.</P>
+<P>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:
+<UL>
+<LI>Not a single dynamic allocation in the core during runtime.
+Everything is pre-allocated at start of ulogd to provide the highest
+possible throughput.</LI>
+<LI>Hash tables in addition to the linked lists. Linked lists are only
+traversed if we really want to access each element of the list.</LI>
+</UL>
+</P>
+
+<H2><A NAME="s2">2. INSTALLATION</A></H2>
+
+
+<H2><A NAME="ss2.1">2.1 Linux kernel</A>
+</H2>
+
+<P>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).</P>
+<P>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.</P>
+
+<H2><A NAME="ss2.2">2.2 ipt_ULOG from netfilter/iptables patch-o-matic</A>
+</H2>
+
+<P>You only need to read this chapter if you have a 2.4.x kernel <=
+2.4.18-pre6.</P>
+<P>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
+<A HREF="http://www.netfilter.org/">http://www.netfilter.org/</A>.</P>
+<P>To run patch-o-matic, just type
+<BLOCKQUOTE><CODE>
+<PRE>
+make patch-o-matic
+</PRE>
+</CODE></BLOCKQUOTE>
+
+in the userspace directory of netfilter CVS.</P>
+
+<H2><A NAME="ss2.3">2.3 ulogd</A>
+</H2>
+
+<H3>Recompiling the source</H3>
+
+<P>Download the ulogd package from
+<A HREF="http://ftp.netfilter.org/pub/ulogd/">http://ftp.netfilter.org/pub/ulogd/</A> and
+untar it. </P>
+<P>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'.</P>
+<P>To compile and install the program, call 'make install'.</P>
+
+<H3>Using a precompiled package</H3>
+
+<P>I also provide a SRPM, which should compile on almost any rpm-based distribution. It is available at
+<A HREF="http://ftp.netfilter.org/pub/ulogd/">http://ftp.netfilter.org/pub/ulogd/</A></P>
+<P>Just download the package and do the usual 'rpm --rebuild <file>'.</P>
+
+<H2><A NAME="s3">3. Configuration</A></H2>
+
+<H2><A NAME="ss3.1">3.1 iptables ULOG target</A>
+</H2>
+
+<H3>Quick Setup</H3>
+
+<P>Just add rules using the ULOG target to your firewalling chain. A very basic
+example:
+<BLOCKQUOTE><CODE>
+<PRE>
+iptables -A FORWARD -j ULOG --ulog-nlgroup 32 --ulog-prefix foo
+</PRE>
+</CODE></BLOCKQUOTE>
+</P>
+<P>To increase logging performance, try to use the
+<BLOCKQUOTE><CODE>
+<PRE>
+--ulog-qthreshold N
+</PRE>
+</CODE></BLOCKQUOTE>
+
+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.</P>
+<P>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.</P>
+<H3>ULOG target reference</H3>
+
+<P>
+<DL>
+<DT><B>--ulog-nlgroup N</B><DD><P>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.</P>
+<DT><B>--ulog-cprange N</B><DD><P>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 <CODE>0</CODE></P>
+<DT><B>--ulog-qthreshold N</B><DD><P>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.</P>
+<DT><B>--ulog-prefix STRING</B><DD><P>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.</P>
+</DL>
+</P>
+
+<H3>ipt_ULOG module parameters</H3>
+
+<P>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:
+<DL>
+<DT><B>nlbufsiz N</B><DD><P>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.</P>
+<DT><B>flushtimeout N</B><DD><P>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.</P>
+</DL>
+
+Example:
+<BLOCKQUOTE><CODE>
+<PRE>
+modprobe ipt_ULOG nlbufsiz=65535 flushtimeout=100
+</PRE>
+</CODE></BLOCKQUOTE>
+
+This would use a buffer size of 64k and a flushtimeout of 100 clockticks (1 second on x86).</P>
+
+<H2><A NAME="ss3.2">3.2 ulogd</A>
+</H2>
+
+<P>ulogd is what this is all about, so let's describe it's configuration...</P>
+<H3>ulogd configfile syntax reference</H3>
+
+<P>All configurable parameters of ulogd are in the configfile, typically located
+at '/etc/ulogd.conf'.</P>
+<P>The following configuration parameters are available:
+<DL>
+<DT><B>nlgroup</B><DD><P>The netlink multicast group, which ulgogd should bind to. This is the same as
+given with the '--ulog-nlgroup' option to iptables.</P>
+<DT><B>logfile</B><DD><P>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.</P>
+<DT><B>loglevel</B><DD><P>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.</P>
+<DT><B>plugin</B><DD><P>This option is followed by a filename of a ulogd plugin, which ulogd shold load
+upon initialization. This option may appear more than once.</P>
+<DT><B>rmem</B><DD><P>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.</P>
+<DT><B>bufsize</B><DD><P>Size of the receive buffer. You should set this to at least the socket receive buffer (rmem).</P>
+</DL>
+</P>
+<H3>ulogd commandline option reference</H3>
+
+<P>Apart from the configfile, there are a couple of commandline options to ulogd:
+<DL>
+<DT><B>-h --help</B><DD><P>Print a help message about the commandline options.</P>
+<DT><B>-V --version</B><DD><P>Print version information about ulogd.</P>
+<DT><B>-d --daemon</B><DD><P>For off into daemon mode. Unless you are debugging, you will want to use this
+most of the time.</P>
+<DT><B>-c --configfile</B><DD><P>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.</P>
+</DL>
+</P>
+
+<H2><A NAME="s4">4. Available plugins</A></H2>
+
+<P>It is important to understand that ulogd without plugins does nothing. It will receive packets, and do nothing with them.</P>
+<P>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/...</P>
+
+<H2><A NAME="ss4.1">4.1 Interpreter plugins</A>
+</H2>
+
+<P>ulogd comes with the following interpreter plugins:</P>
+<H3>ulogd_BASE.so</H3>
+
+<P>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.</P>
+<H3>ulogd_PWSNIFF.so</H3>
+
+<P>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.</P>
+<H3>ulogd_LOCAL.so</H3>
+
+<P>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.</P>
+
+<H2><A NAME="ss4.2">4.2 Output plugins</A>
+</H2>
+
+<P>ulogd comes with the following output plugins:</P>
+
+<H3>ulogd_OPRINT.so</H3>
+
+<P>A very simple output module, dumping all packets in the format
+<BLOCKQUOTE><CODE>
+<PRE>
+===>PACKET BOUNDARY
+key=value
+key=value
+...
+===>PACKET BOUNDARY
+...
+</PRE>
+</CODE></BLOCKQUOTE>
+
+to a file. The only useful application is debugging.</P>
+<P>The module defines the following configuration directives:
+<DL>
+<DT><B>dumpfile</B><DD><P>The filename where it should log to. The default is
+<CODE>/var/log/ulogd.pktlog</CODE></P>
+</DL>
+</P>
+
+<H3>ulogd_LOGEMU.so</H3>
+
+<P>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.</P>
+<P>The module defines the following configuration directives:
+<DL>
+<DT><B>file</B><DD><P>The filename where it should log to. The default is
+<CODE>/var/log/ulogd.syslogemu</CODE></P>
+<DT><B>sync</B><DD><P>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 <CODE>0</CODE></P>
+</DL>
+</P>
+
+<H3>ulogd_MYSQL.so</H3>
+
+<P>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)</P>
+
+<P>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.</P>
+
+<P>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.</P>
+
+<P>You may want to have a look at the file '<CODE>doc/mysql.table</CODE>' 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.</P>
+
+<P>The module defines the following configuration directives:
+<DL>
+<DT><B>table</B><DD><P>Name of the table to which ulogd should log.</P>
+<DT><B>ldb</B><DD><P>Name of the mysql database.</P>
+<DT><B>host</B><DD><P>Name of the mysql database host.</P>
+<DT><B>port</B><DD><P>TCP port number of mysql database server.</P>
+<DT><B>user</B><DD><P>Name of the mysql user.</P>
+<DT><B>pass</B><DD><P>Password for mysql.</P>
+</DL>
+</P>
+
+<H3>ulogd_PGSQL.so</H3>
+
+<P>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)</P>
+
+<P>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.</P>
+
+<P>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.</P>
+
+<P>You may want to have a look at the file '<CODE>doc/mysql.table</CODE>' 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.</P>
+
+<P>The module defines the following configuration directives:
+<DL>
+<DT><B>table</B><DD><P>Name of the table to which ulogd should log.</P>
+<DT><B>db</B><DD><P>Name of the database.</P>
+<DT><B>host</B><DD><P>Name of the mysql database host.</P>
+<DT><B>port</B><DD><P>TCP port number of database server.</P>
+<DT><B>user</B><DD><P>Name of the sql user.</P>
+<DT><B>pass</B><DD><P>Password for sql user.</P>
+</DL>
+</P>
+
+<H3>ulogd_PCAP.so</H3>
+
+<P>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.</P>
+<P>The module defines the following configuration directives:
+<DL>
+<DT><B>file</B><DD><P>The filename where it should log to. The default is:
+<CODE>/var/log/ulogd.pcap</CODE></P>
+<DT><B>sync</B><DD><P>Set this to <CODE>1</CODE> 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 <CODE>0</CODE></P>
+</DL>
+</P>
+
+<H3>ulogd_SQLITE3.so</H3>
+
+<P>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)</P>
+
+<P>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.</P>
+
+<P>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.</P>
+
+<P>You may want to have a look at the file '<CODE>doc/sqlite3.table</CODE>' 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.</P>
+
+<P>The module defines the following configuration directives:
+<DL>
+<DT><B>table</B><DD><P>Name of the table to which ulogd should log.</P>
+<DT><B>db</B><DD><P>Name of the database.</P>
+<DT><B>buffer</B><DD><P>Size of the sqlite buffer.</P>
+</DL>
+</P>
+<H3>ulogd_SYSLOG.so</H3>
+
+<P>An output plugin that really logs via syslogd. Lines will look exactly like printed with traditional LOG target.</P>
+
+<P>The module defines the following configuration directives:
+<DL>
+<DT><B>facility</B><DD><P>The syslog facility (LOG_DAEMON, LOG_KERN, LOG_LOCAL0 .. LOG_LOCAL7, LOG_USER)</P>
+<DT><B>level</B><DD><P>The syslog level (LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG)</P>
+</DL>
+</P>
+<H2><A NAME="s5">5. QUESTIONS / COMMENTS</A></H2>
+
+<P>All comments / questions / ... are appreciated.</P>
+<P>Just drop me a note to laforge@gnumonks.org</P>
+<P>Please note also that there is now a mailinglist, ulogd@lists.gnumonks.org.
+You can subscribe at
+<A HREF="http://lists.gnumonks.org/mailman/listinfo/ulogd/">http://lists.gnumonks.org/mailman/listinfo/ulogd/</A>.</P>
+<P>
+The preferred method for reporting bugs is the netfilter bugzilla system,
+available at
+<A HREF="http://bugzilla.netfilter.org/">http://bugzilla.netfilter.org/</A>.</P>
+
+</BODY>
+</HTML>
--- /dev/null
+<!doctype linuxdoc system>
+
+<!-- $Id: ulogd.sgml 5846 2005-07-12 15:33:23Z laforge $ -->
+
+<article>
+
+<title>ULOGD - the Userspace Logging Daemon</title>
+<author>Harald Welte <laforge@gnumonks.org></author>
+<date>Revision $Revision: 5846 $, $Date: 2005-07-12 17:33:23 +0200 (Tue, 12 Jul 2005) $</date>
+
+<abstract>
+This is the documentation for <tt>ulogd</tt>, the Userspace logging daemon.
+ulogd makes use of the Linux >= 2.4.x packet filter subsystem (iptables) and
+the ULOG target for iptables.
+</abstract>
+
+<toc>
+
+<sect>DESIGN
+
+<sect1>CONCEPT
+<p>
+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:
+<p>
+<descrip>
+<tag>Interpreter plugins</tag>
+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.
+
+<tag>Output plugins</tag>
+... 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.
+
+</descrip>
+
+<sect1>DETAILS
+<p>
+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.
+<p>
+Rusty advised me to use some kind of type-key-value triples, which is in fact
+what I implemented.
+<p>
+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:
+<itemize>
+<item>Not a single dynamic allocation in the core during runtime.
+Everything is pre-allocated at start of ulogd to provide the highest
+possible throughput.
+<item>Hash tables in addition to the linked lists. Linked lists are only
+traversed if we really want to access each element of the list.
+</itemize>
+
+<sect>INSTALLATION
+<p>
+<sect1>Linux kernel
+<p>
+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).
+<p>
+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.
+
+<sect1>ipt_ULOG from netfilter/iptables patch-o-matic
+<p>
+You only need to read this chapter if you have a 2.4.x kernel <=
+2.4.18-pre6.
+<p>
+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 <URL URL="http://www.netfilter.org/">.
+<p>
+To run patch-o-matic, just type
+<tscreen><verb>
+make patch-o-matic
+</verb></tscreen>
+in the userspace directory of netfilter CVS.
+
+<sect1>ulogd
+<sect2>Recompiling the source
+<p>
+Download the ulogd package from <URL URL="http://ftp.netfilter.org/pub/ulogd/"> and
+untar it.
+<p>
+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'.
+<p>
+To compile and install the program, call 'make install'.
+
+<sect2>Using a precompiled package
+<p>
+I also provide a SRPM, which should compile on almost any rpm-based distribution. It is available at <URL URL="http://ftp.netfilter.org/pub/ulogd/">
+<p>
+Just download the package and do the usual 'rpm --rebuild <file>'.
+
+<sect>Configuration
+<sect1>iptables ULOG target
+<sect2>Quick Setup
+<p>
+Just add rules using the ULOG target to your firewalling chain. A very basic
+example:
+<tscreen><verb>
+iptables -A FORWARD -j ULOG --ulog-nlgroup 32 --ulog-prefix foo
+</verb></tscreen>
+<p>
+To increase logging performance, try to use the
+<tscreen><verb>
+--ulog-qthreshold N
+</verb></tscreen>
+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.
+<p>
+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.
+<sect2>ULOG target reference
+<p>
+<descrip>
+<tag>--ulog-nlgroup N</tag>
+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.
+<tag>--ulog-cprange N</tag>
+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 <tt>0</tt>
+<tag>--ulog-qthreshold N</tag>
+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.
+<tag>--ulog-prefix STRING</tag>
+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.
+</descrip>
+
+<sect2>ipt_ULOG module parameters
+<p>
+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:
+<descrip>
+<tag>nlbufsiz N</tag>
+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.
+<tag>flushtimeout N</tag>
+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.
+</descrip>
+Example:
+<tscreen><verb>
+modprobe ipt_ULOG nlbufsiz=65535 flushtimeout=100
+</verb></tscreen>
+This would use a buffer size of 64k and a flushtimeout of 100 clockticks (1 second on x86).
+
+<sect1>ulogd
+<p>
+ulogd is what this is all about, so let's describe it's configuration...
+<sect2>ulogd configfile syntax reference
+<p>
+All configurable parameters of ulogd are in the configfile, typically located
+at '/etc/ulogd.conf'.
+<p>
+The following configuration parameters are available:
+<descrip>
+<tag>nlgroup</tag>
+The netlink multicast group, which ulgogd should bind to. This is the same as
+given with the '--ulog-nlgroup' option to iptables.
+<tag>logfile</tag>
+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.
+<tag>loglevel</tag>
+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.
+<tag>plugin</tag>
+This option is followed by a filename of a ulogd plugin, which ulogd shold load
+upon initialization. This option may appear more than once.
+<tag>rmem</tag>
+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.
+<tag>bufsize</tag>
+Size of the receive buffer. You should set this to at least the socket receive buffer (rmem).
+</descrip>
+<sect2>ulogd commandline option reference
+<p>
+Apart from the configfile, there are a couple of commandline options to ulogd:
+<descrip>
+<tag>-h --help</tag>
+Print a help message about the commandline options.
+<tag>-V --version</tag>
+Print version information about ulogd.
+<tag>-d --daemon</tag>
+For off into daemon mode. Unless you are debugging, you will want to use this
+most of the time.
+<tag>-c --configfile</tag>
+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.
+</descrip>
+
+<sect>Available plugins
+<p>
+It is important to understand that ulogd without plugins does nothing. It will receive packets, and do nothing with them.
+<p>
+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/...
+
+<sect1>Interpreter plugins
+<p>
+ulogd comes with the following interpreter plugins:
+<sect2>ulogd_BASE.so
+<p>
+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.
+<sect2>ulogd_PWSNIFF.so
+<p>
+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.
+<sect2>ulogd_LOCAL.so
+<p>
+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.
+
+<sect1>Output plugins
+<p>
+ulogd comes with the following output plugins:
+
+<sect2>ulogd_OPRINT.so
+<p>
+A very simple output module, dumping all packets in the format
+<tscreen><verb>
+===>PACKET BOUNDARY
+key=value
+key=value
+...
+===>PACKET BOUNDARY
+...
+</verb></tscreen>
+to a file. The only useful application is debugging.
+<p>The module defines the following configuration directives:
+<descrip>
+<tag>dumpfile</tag>
+The filename where it should log to. The default is
+<tt>/var/log/ulogd.pktlog</tt>
+</descrip>
+
+<sect2>ulogd_LOGEMU.so
+<p>
+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.
+<p>
+The module defines the following configuration directives:
+<descrip>
+<tag>file</tag>The filename where it should log to. The default is
+<tt>/var/log/ulogd.syslogemu</tt>
+<tag>sync</tag>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 <tt>0</tt>
+</descrip>
+
+<sect2>ulogd_MYSQL.so
+<p>
+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)
+
+<p>
+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.
+
+<p>
+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.
+
+<p>
+You may want to have a look at the file '<tt>doc/mysql.table</tt>' 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.
+
+<p>
+The module defines the following configuration directives:
+<descrip>
+<tag>table</tag>
+Name of the table to which ulogd should log.
+<tag>ldb</tag>
+Name of the mysql database.
+<tag>host</tag>
+Name of the mysql database host.
+<tag>port</tag>
+TCP port number of mysql database server.
+<tag>user</tag>
+Name of the mysql user.
+<tag>pass</tag>
+Password for mysql.
+</descrip>
+
+<sect2>ulogd_PGSQL.so
+<p>
+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)
+
+<p>
+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.
+
+<p>
+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.
+
+<p>
+You may want to have a look at the file '<tt>doc/mysql.table</tt>' 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.
+
+<p>
+The module defines the following configuration directives:
+<descrip>
+<tag>table</tag>
+Name of the table to which ulogd should log.
+<tag>db</tag>
+Name of the database.
+<tag>host</tag>
+Name of the mysql database host.
+<tag>port</tag>
+TCP port number of database server.
+<tag>user</tag>
+Name of the sql user.
+<tag>pass</tag>
+Password for sql user.
+</descrip>
+
+<sect2>ulogd_PCAP.so
+<p>
+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:
+<descrip>
+<tag>file</tag>
+The filename where it should log to. The default is:
+<tt>/var/log/ulogd.pcap</tt>
+<tag>sync</tag>
+Set this to <tt>1</tt> 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 <tt>0</tt>
+</descrip>
+
+<sect2>ulogd_SQLITE3.so
+<p>
+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)
+
+<p>
+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.
+
+<p>
+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.
+
+<p>
+You may want to have a look at the file '<tt>doc/sqlite3.table</tt>' 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.
+
+<p>
+The module defines the following configuration directives:
+<descrip>
+<tag>table</tag>
+Name of the table to which ulogd should log.
+<tag>db</tag>
+Name of the database.
+<tag>buffer</tag>
+Size of the sqlite buffer.
+</descrip>
+</sect2>
+
+<sect2>ulogd_SYSLOG.so
+<p>
+An output plugin that really logs via syslogd. Lines will look exactly like printed with traditional LOG target.
+
+<p>
+The module defines the following configuration directives:
+<descrip>
+<tag>facility</tag>
+The syslog facility (LOG_DAEMON, LOG_KERN, LOG_LOCAL0 .. LOG_LOCAL7, LOG_USER)
+<tag>level</tag>
+The syslog level (LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG)
+</descrip>
+</sect2>
+
+<sect> QUESTIONS / COMMENTS
+<p>
+All comments / questions / ... are appreciated.
+<p>
+Just drop me a note to laforge@gnumonks.org
+<p>
+Please note also that there is now a mailinglist, ulogd@lists.gnumonks.org.
+You can subscribe at
+<URL URL="http://lists.gnumonks.org/mailman/listinfo/ulogd/">.
+<p>
+The preferred method for reporting bugs is the netfilter bugzilla system,
+available at <URL URL="http://bugzilla.netfilter.org/">.
+
+</article>
--- /dev/null
+ 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 (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
+
+
+ ______________________________________________________________________
+
+ \e[1m1. DESIGN\e[0m
+
+ \e[1m1.1. CONCEPT\e[0m
+
+ 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:
+
+
+ \e[1mInterpreter plugins\e[0m
+ 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.
+
+
+ \e[1mOutput plugins\e[0m
+ ... 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.
+
+
+
+ \e[1m1.2. DETAILS\e[0m
+
+ 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.
+
+
+ \e[1m2. INSTALLATION\e[0m
+
+
+ \e[1m2.1. Linux kernel\e[0m
+
+ 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.
+
+
+ \e[1m2.2. ipt_ULOG from netfilter/iptables patch-o-matic\e[0m
+
+ 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.
+
+
+ \e[1m2.3. ulogd\e[0m
+
+ \e[1m2.3.1. Recompiling the source\e[0m
+
+ 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'.
+
+
+ \e[1m2.3.2. Using a precompiled package\e[0m
+
+ 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>'.
+
+
+ \e[1m3. Configuration\e[0m
+
+ \e[1m3.1. iptables ULOG target\e[0m
+
+ \e[1m3.1.1. Quick Setup\e[0m
+
+ 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.
+
+ \e[1m3.1.2. ULOG target reference\e[0m
+
+
+ \e[1m--ulog-nlgroup N\e[0m
+ 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.
+
+ \e[1m--ulog-cprange N\e[0m
+ 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
+
+ \e[1m--ulog-qthreshold N\e[0m
+ 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.
+
+ \e[1m--ulog-prefix STRING\e[0m
+ 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.
+
+
+ \e[1m3.1.3. ipt_ULOG module parameters\e[0m
+
+ 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:
+
+ \e[1mnlbufsiz N\e[0m
+ 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.
+
+ \e[1mflushtimeout N\e[0m
+ 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).
+
+
+ \e[1m3.2. ulogd\e[0m
+
+ ulogd is what this is all about, so let's describe it's
+ configuration...
+
+ \e[1m3.2.1. ulogd configfile syntax reference\e[0m
+
+ All configurable parameters of ulogd are in the configfile, typically
+ located at '/etc/ulogd.conf'.
+ The following configuration parameters are available:
+
+ \e[1mnlgroup\e[0m
+ The netlink multicast group, which ulgogd should bind to. This
+ is the same as given with the '--ulog-nlgroup' option to
+ iptables.
+
+ \e[1mlogfile\e[0m
+ 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.
+
+ \e[1mloglevel\e[0m
+ 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.
+
+ \e[1mplugin\e[0m
+ This option is followed by a filename of a ulogd plugin, which
+ ulogd shold load upon initialization. This option may appear
+ more than once.
+
+ \e[1mrmem\e[0m
+ 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.
+
+ \e[1mbufsize\e[0m
+ Size of the receive buffer. You should set this to at least the
+ socket receive buffer (rmem).
+
+ \e[1m3.2.2. ulogd commandline option reference\e[0m
+
+ Apart from the configfile, there are a couple of commandline options
+ to ulogd:
+
+ \e[1m-h --help\e[0m
+ Print a help message about the commandline options.
+
+ \e[1m-V --version\e[0m
+ Print version information about ulogd.
+
+ \e[1m-d --daemon\e[0m
+ For off into daemon mode. Unless you are debugging, you will
+ want to use this most of the time.
+
+ \e[1m-c --configfile\e[0m
+ 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.
+
+
+ \e[1m4. Available plugins\e[0m
+
+ 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/...
+
+ \e[1m4.1. Interpreter plugins\e[0m
+
+ ulogd comes with the following interpreter plugins:
+
+ \e[1m4.1.1. ulogd_BASE.so\e[0m
+
+ 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.
+
+ \e[1m4.1.2. ulogd_PWSNIFF.so\e[0m
+
+ 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.
+
+ \e[1m4.1.3. ulogd_LOCAL.so\e[0m
+
+ 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.
+
+
+ \e[1m4.2. Output plugins\e[0m
+
+ ulogd comes with the following output plugins:
+
+
+ \e[1m4.2.1. ulogd_OPRINT.so\e[0m
+
+ 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:
+
+ \e[1mdumpfile\e[0m
+ The filename where it should log to. The default is
+ /var/log/ulogd.pktlog
+
+
+ \e[1m4.2.2. ulogd_LOGEMU.so\e[0m
+
+ 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:
+
+ \e[1mfile\e[0m
+ The filename where it should log to. The default is
+ /var/log/ulogd.syslogemu
+
+ \e[1msync\e[0m
+ 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
+
+
+ \e[1m4.2.3. ulogd_MYSQL.so\e[0m
+
+ 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:
+
+ \e[1mtable\e[0m
+ Name of the table to which ulogd should log.
+
+ \e[1mldb\e[0m
+ Name of the mysql database.
+
+ \e[1mhost\e[0m
+ Name of the mysql database host.
+
+ \e[1mport\e[0m
+ TCP port number of mysql database server.
+
+ \e[1muser\e[0m
+ Name of the mysql user.
+
+ \e[1mpass\e[0m
+ Password for mysql.
+
+
+ \e[1m4.2.4. ulogd_PGSQL.so\e[0m
+
+ 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:
+
+ \e[1mtable\e[0m
+ Name of the table to which ulogd should log.
+
+ \e[1mdb \e[22mName of the database.
+
+ \e[1mhost\e[0m
+ Name of the mysql database host.
+
+ \e[1mport\e[0m
+ TCP port number of database server.
+
+ \e[1muser\e[0m
+ Name of the sql user.
+
+ \e[1mpass\e[0m
+ Password for sql user.
+
+
+ \e[1m4.2.5. ulogd_PCAP.so\e[0m
+
+ 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:
+
+ \e[1mfile\e[0m
+ The filename where it should log to. The default is:
+ /var/log/ulogd.pcap
+
+ \e[1msync\e[0m
+ 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
+
+
+ \e[1m4.2.6. ulogd_SQLITE3.so\e[0m
+
+ 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:
+
+ \e[1mtable\e[0m
+ Name of the table to which ulogd should log.
+
+ \e[1mdb \e[22mName of the database.
+
+ \e[1mbuffer\e[0m
+ Size of the sqlite buffer.
+
+ \e[1m4.2.7. ulogd_SYSLOG.so\e[0m
+
+ 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:
+
+ \e[1mfacility\e[0m
+ The syslog facility (LOG_DAEMON, LOG_KERN, LOG_LOCAL0 ..
+ LOG_LOCAL7, LOG_USER)
+
+ \e[1mlevel\e[0m
+ The syslog level (LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR,
+ LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG)
+
+ \e[1m5. QUESTIONS / COMMENTS\e[0m
+
+ 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/>.
+
+
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<drl>
+ <machine id="11" limit="10" commfabric="MESH" branch="0" accounting="STANDARD" ewma="0.1" intervals="1">
+ <peer>127.0.0.1</peer>
+ </machine>
+</drl>
--- /dev/null
+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.
--- /dev/null
+# 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 <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> 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 <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> 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
--- /dev/null
+#
+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)
--- /dev/null
+--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:
+
+<?xml version="1.0" encoding="UTF-8"?>
+<drl>
+ <machine id="11" limit="10" commfabric="MESH" branch="0" accounting="STANDARD" ewma="0.1" intervals="2">
+ <peer>137.110.222.242</peer>
+ <peer>137.110.222.243</peer>
+ </machine>
+ <set id="20" limit="15" commfabric="GOSSIP" branch="1" accounting="STANDARD" ewma="0.1" intervals="3">
+ <peer>137.110.222.240</peer>
+ <xid>1f9</xid>
+ </set>
+ <set id="21" limit="25" commfabric="MESH" branch="0" accounting="STANDARD" ewma="0.1" intervals="1">
+ <peer>137.110.222.245</peer>
+ <xid>1fa</xid>
+ <guid>20</guid>
+ </set>
+</drl>
+
+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 <peer>
+tags inside the identity specifier. In addition to peers, set identities must
+also have at least one <xid> or <guid> tag. <xid> tags refer to slice ids for
+slices that are available at the local node. <guid> tags refer to the globally
+unique id of another set identity.
--- /dev/null
+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 <rpm> | cpio -diu
+but u is don't prompt. so I'll issue
+rpm2cpio <rpm> | 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.
+
+!!!!!<CHANGE TO SYSNET34>!!!!!
+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.
+
+<changing kernel config files in build/linux-x-x-x/configs directory
+i686-smp-plab
+i686-onelab
+i686-planetlab
+all added CONFIG_NET_SCH_NETEM=m
+
+
+2-1-08
+
+GRD dropping. Use netem, which is accessible also through tc.
+I believe what we want to do is put the netem on the interface for all
+traffic? OK, that's not going to work for setting up for traffic that goes
+to "blessed" destinations.
+
+We will 1.) set up a qdisc for netem on the device, and have it affect all
+traffic in the htb first.
+Then we will try to set up a netem only for certain traffic in the htb.
+
+
+Can you list all of the destinations or iproute2 rules used to classify
+traffic to tc classes?
+
+so we have a couple of options. We can look at the tc source in iproute2
+code I downloaded on sysnet35. However, this is pretty low-level code; we
+have to communicate over a netlink socket in order to feed commands to TC.
+The alternative is to fork/exec from ulogd when we need to issue new tc
+commands. In the short term, let's do this.
+
+
+
+12-31-08
+
+so the hack is to change the ceilings on all of the child slice classes.
+That's one thing to do for all outbound traffic. Theoretically we should
+be able to just set the rule for 1:10 but that doesn't seem to be working.
+
+
+1.) /usr/share/util-vserver/bwlimit.py -v init
+2.) /usr/share/util-vserver/bwlimit.py -v on pl_drl 1 8bit 1gbit 8bit 1gbit
+3.) /usr/share/util-vserver/bwlimit.py -v on pl_drl_two 1 8bit 1gbit 8bit 1gbit
+
+You can change the 1:10 class, and then you can off/on the slice limits.
+The script makes sure to set the ceilings of the children classes to the
+ceiling of the parents.
+
+Fine. That's how they want it, that's how they'll get it. What we need
+to make sure is that the individual slices still share the outgoing
+bandwidth appropriately.
+
+I'm not too sure what the traffic control does for you when they share
+everything identically. Let's assume that they want it.
+
+For FPS the limiter is a token bucket. We want to simply set the rate to
+something with this token bucket. We should be able to do this exactly
+with the right TC command. No problem.
+
+For GRD the limiter is a packet dropper. Drop X % of packets. Let me
+look at the outgoing schedulers. It doesn't look like we will be able to
+do it with TC. We may be able to do it with a netfilter module. Probably
+a custom module. They probably use netfilter commands to assign packets to
+tc classes anyhow. so we need to add similar rules.
+
+So for now let's focus on FPS. In this case we need to be able to
+interact with TC from the ulogd program, either through a call or
+directly.
+
+
+
+
+
+12-29-08
+
+check this out. The example looks familiar to how tc is used in plab.
+http://edseek.com/~jasonb/articles/traffic_shaping/class.html
+
+
+qdiscs are added at the very bottom for each class whose minor number is
+the xid. There is one parent qdisc which allows you to add classes. That
+is the htb classfull qdisc. The bottom qdisc's are pfifo's which I
+believe are classless. pfifo is the scheduler that all leaf nodes of
+classful qdiscs are assigned. The only thing you can do is to determine
+the size the queue. This is scheduling, not shaping.
+
+You can add other schedulers: sfq, which tries to be flow fair.
+tbf: token bucket filter. tbf is now a classful qdisc.
+
+
+You had better make sure that your rates of your child classes do not
+exceed the rate of the parent class. those are the minimums. What about
+the ceilings? That says how much you can borrow. Classes borrow in
+proportion to the minimum rates that they are assigned. Individual
+ceilings should not exceed the parents rate. Because it says how much you
+can borrow when no one else is using anything.
+
+So do I have to write all new rules for all slices that are active when we
+want to constrain them all?
+
+What happens when the parents rate/ceiling is less than the maximum that
+they can borrow? That apparently doesn't do any damm thing. But this is
+probably why the script makes sure that the ceilings don't go above the
+1:10 or 1:1. It never checks for 1:20, which is probably b/c they always
+expect it to have a ceiling equal to bandwidth max.
+
+OK. If we set the ceiling of the child class to the ceiling of the
+parent, tokens are borrowed appropriately. If the ceiling is greater of
+the child, then it looks like cburst has a lot to do with it. So I have
+to see what is happening with cburst.
+
+
+Setting 1:1 to rate 5mb no ceiling
+setting 1:10 to rate 8 ceil 5mb
+setting 1:1myslice rate 8 ceil 1gbit
+
+This configuration does not work.
+
+when 1myslice ceil is > 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 <no help>
+yum install ulogd-mysql.i386 <no help>
+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 <name> 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.
+
+
+
--- /dev/null
+/*-
+ * 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 <sys/cdefs.h>
+
+/*
+ * 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_ */
--- /dev/null
+/* 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_ */
--- /dev/null
+/* 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 <inttypes.h>
+#include <sys/time.h>
+#include <time.h>
+
+/** 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_ */
--- /dev/null
+/* See the DRL-LICENSE file for this file's software license. */
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <errno.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#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;
+}
--- /dev/null
+/* 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_ */
--- /dev/null
+/* See the DRL-LICENSE file for this file's software license. */
+
+/** Allows us to use pthread_rwlocks. */
+#define _XOPEN_SOURCE 600
+
+/* malloc(), NULL */
+#include <stdlib.h>
+
+/* getpid() */
+#include <unistd.h>
+
+/* Socket functions. */
+#include <sys/socket.h>
+
+/* memset() */
+#include <string.h>
+
+/* perror() */
+#include <errno.h>
+
+/* FD_ZERO() */
+#include <sys/select.h>
+
+#include <assert.h>
+
+#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);
+}
--- /dev/null
+/* See the DRL-LICENSE file for this file's software license. */
+
+#ifndef _DRL_STATE_
+#define _DRL_STATE_
+
+#define _XOPEN_SOURCE 600
+
+/* FILE */
+#include <stdio.h>
+
+/* uint32_t */
+#include <sys/types.h>
+#include <inttypes.h>
+
+/* in_addr_t, in_port_t */
+#include <arpa/inet.h>
+
+/* pthread functions. */
+#include <pthread.h>
+
+/* fd_set */
+#include <sys/select.h>
+
+/* 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_ */
--- /dev/null
+/* 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);
+ }
+}
--- /dev/null
+/* See the DRL-LICENSE file for this file's software license. */
+#include <stdio.h>
+
+#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;
+}
--- /dev/null
+/* See the DRL-LICENSE file for this file's software license. */
+
+#ifndef _LOGGING_H_
+#define _LOGGING_H_
+
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#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_ */
--- /dev/null
+/* See the DRL-LICENSE file for this file's software license. */
+
+#define _XOPEN_SOURCE 600
+
+/* Debug output. */
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Socket functions. */
+#include <sys/types.h>
+#include <sys/socket.h>
+
+/* Byte ordering and address structures. */
+#include <arpa/inet.h>
+
+/* memset() */
+#include <string.h>
+
+/* close() & usleep */
+#include <unistd.h>
+
+/* Mutex lock/unlock. */
+#include <pthread.h>
+
+/* perror() */
+#include <errno.h>
+
+/* select() w/ timeout */
+#include <sys/select.h>
+#include <sys/time.h>
+
+/* assert() */
+#include <assert.h>
+
+/* sigaddset(), sigemptyset(), SIGHUP, etc. */
+#include <signal.h>
+
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <sys/poll.h>
+
+#include <arpa/inet.h>
+#include <time.h>
+#include <signal.h>
+#include <math.h>
+#include <limits.h>
+
+#include <pthread.h>
+#include <unistd.h>
+
+#include <netdb.h>
+#include <ifaddrs.h> /* defines getifaddrs */
+#include <string.h>
+
+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
--- /dev/null
+/* 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 <inttypes.h>
+
+#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<htb_node>)*/
+ 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
--- /dev/null
+/* See the DRL-LICENSE file for this file's software license. */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+
+#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;
+}
--- /dev/null
+/* 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 <inttypes.h>
+
+#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__ */
--- /dev/null
+/* See the DRL-LICENSE file for this file's software license. */
+
+#include <arpa/inet.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+
+#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;
+}
--- /dev/null
+/* 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 <inttypes.h>
+
+/** 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_ */
--- /dev/null
+/* See the DRL-LICENSE file for this file's software license. */
+
+#include <arpa/inet.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+
+#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;
+}
--- /dev/null
+/* 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 <inttypes.h>
+
+/** 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_ */
--- /dev/null
+/* See the DRL-LICENSE file for this file's software license. */
+
+/*
+ * ulogd output target for DRL: GRD and FPS
+ *
+ * Ken Yocum <kyocum@cs.ucsd.edu>
+ *
+ * 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 <kyocum@cs.ucsd.edu>
+ * 2007
+ *
+ * Some code appropriated from ulogd_NETFLOW:
+ *
+ * Mark Huang <mlhuang@cs.princeton.edu>
+ * 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 <stdio.h>
+#include <stdlib.h>
+
+/* va_start() and friends */
+#include <stdarg.h>
+
+/* ispunct() */
+#include <ctype.h>
+
+/* strstr() and friends */
+#include <string.h>
+
+/* dirname() and basename() */
+#include <libgen.h>
+
+/* fork() and wait() */
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+/* errno and assert() */
+#include <errno.h>
+#include <assert.h>
+
+/* getopt_long() */
+#include <getopt.h>
+
+/* time() and friends */
+#include <time.h>
+#include <sys/time.h>
+
+/* inet_aton() */
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+/* ICMP definitions */
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+
+/* stat() */
+#include <sys/stat.h>
+
+/* pthread_create() */
+#include <pthread.h>
+
+/* flock() */
+#include <sys/file.h>
+
+/* Signal definitions - so that we can catch SIGHUP and update config. */
+#include <signal.h>
+
+#include <ulogd/ulogd.h>
+#include <ulogd/conffile.h>
+
+/* Perhaps useful for files within vservers? */
+#if !defined(STANDALONE) && HAVE_LIBPROPER
+#include <proper/prop.h>
+#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 <dmalloc.h>
+#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();
+}
--- /dev/null
+/* 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;i<len;i++){ /* word-wise bit compare would be faster */
+ if(((char*)one)[i] != ((char*)two)[i]){
+ return(false);
+ }
+ }
+ return(true);
+}
+
+/* pass in something at least 20 bytes long */
+void ip_from_bytes(uint32_t addr, char *buf){
+ int i;
+ unsigned char *caddr = (unsigned char*) &addr;
+ if (am_big_endian()){
+ i = sprintf(buf,"%d.%d.%d.%d",caddr[0],caddr[1],caddr[2],caddr[3]);
+ } else {
+ i = sprintf(buf,"%d.%d.%d.%d",caddr[3],caddr[2],caddr[1],caddr[0]);
+ }
+ return;
+}
+
+
+void init_hashing(void){
+ util_salt = getpid() ^ time(NULL); // same as ulogd_drl
+}
+
+/* some stupid generic hash function things */
+/* just return a map_handle */
+map_handle allocate_map(void) {
+ map_handle map;
+ map = (map_handle) malloc(sizeof(struct map));
+ if (map == NULL) {
+ printlog(LOG_WARN, "allocate_map failed.");
+ return NULL;
+ }
+
+ memset(map,0,sizeof(struct map));
+ map->iterator = 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;i<GENERIC_HASH_SIZE;i++){
+ nxt_me = (struct map_entry*) (map->table[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;i<keylen;i++){
+ printf("[%x]",((char*)key)[i]);
+ }
+ printf(" Hashes to index (%d)\n", index);
+#endif
+
+ nxt_me = (struct map_entry*) map->table[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;i<map->size;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):");
+ }
+}
--- /dev/null
+/* 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 <linux/jhash.h>
+
+#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
--- /dev/null
+#
+
+# 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)
--- /dev/null
+#ifndef _CHTONS_H_
+#define _CHTONS_H_
+
+#include <endian.h>
+
+#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
--- /dev/null
+/* printpkt.c
+ *
+ * build something looking like a iptables LOG message
+ *
+ * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <ulogd/ulogd.h>
+#include <ulogd/conffile.h>
+
+#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;
+}
--- /dev/null
+#ifndef _PRINTPKT_H
+#define _PRINTPKT_H
+
+int printpkt_print(ulog_iret_t *res, char *buf, int prefix);
+int printpkt_init(void);
+
+#endif
--- /dev/null
+/* 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 <laforge@gnumonks.org>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/ip.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/udp.h>
+#include <ulogd/ulogd.h>
+#include <ulogd/gre.h>
+
+/***********************************************************************
+ * 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();
+}
--- /dev/null
+/* ulogd_LOCAL.c, Version 0.3
+ *
+ * ulogd interpreter plugin for: - local time of packet
+ * - hostname of localhost
+ *
+ * (C) 2001-2002 by Florent AIDE <faide@alphacent.com>
+ * with the help of Moez MKADMI <moez.mka@voila.fr>
+ * shamelessly ripped from Harald Welte
+ *
+ * 2002 extended by Martin Kaehmer <teg@mompl.org>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <ulogd/ulogd.h>
+
+#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();
+}
--- /dev/null
+/* 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 <laforge@gnumonks.org>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ulogd/ulogd.h>
+#include <ulogd/conffile.h>
+#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);
+}
--- /dev/null
+/* ulogd_MAC.c, Version $Revision: 5252 $
+ *
+ * ulogd output target for logging to a file
+ *
+ * (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ulogd/ulogd.h>
+#include <ulogd/conffile.h>
+
+#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, "<none>");
+ 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);
+}
--- /dev/null
+/* ulogd_PWSNIFF.c, Version $Revision: 5372 $
+ *
+ * ulogd logging interpreter for POP3 / FTP like plaintext passwords.
+ *
+ * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/ip.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include "chtons.h"
+#include <ulogd/ulogd.h>
+
+#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();
+}
--- /dev/null
+/* 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 <laforge@gnumonks.org>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+#include <ulogd/ulogd.h>
+#include <ulogd/conffile.h>
+#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);
+}
--- /dev/null
+#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 */
--- /dev/null
+/* config file parser functions
+ *
+ * (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ *
+ * $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 <sys/types.h>
+
+/* 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 */
--- /dev/null
+#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_ */
--- /dev/null
+#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 <laforge@gnumonks.org>
+ *
+ * this code is released under the terms of GNU GPL
+ *
+ * $Id: ulogd.h 5369 2005-05-04 01:16:57Z laforge $
+ */
+
+#include <libipulog/libipulog.h>
+#include <stdio.h>
+#include <signal.h> /* 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 */
--- /dev/null
+#!/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
--- /dev/null
+#
+
+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
--- /dev/null
+#ifndef _LIBIPULOG_H
+#define _LIBIPULOG_H
+
+/* $Id: libipulog.h 4915 2003-05-04 10:00:10Z laforge $ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <asm/types.h>
+#include <linux/netlink.h>
+#include <net/if.h>
+#include <linux/netfilter_ipv4/ipt_ULOG.h>
+
+/* 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 */
--- /dev/null
+/*
+ * libipulog.c, $Revision: 5371 $
+ *
+ * netfilter ULOG userspace library.
+ *
+ * (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <net/if.h>
+#include <libipulog/libipulog.h>
+#if HAVE_LIBPROPER
+#include <proper/prop.h>
+#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);
+}
+
--- /dev/null
+/* 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 <laforge@gnumonks.org>
+ *
+ * this code is released under the terms of GNU GPL
+ *
+ * $Id: ulog_test.c 5293 2005-03-11 11:47:53Z laforge $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libipulog/libipulog.h>
+
+#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;
+}
--- /dev/null
+#
+
+# 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)
--- /dev/null
+#
+
+# 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)
--- /dev/null
+/* ulogd_MYSQL.c, Version $Revision: 5875 $
+ *
+ * ulogd output plugin for logging to a MySQL database
+ *
+ * (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
+ *
+ * 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 <alex@ynfonatic.de>:
+ * Added a compability option for older MySQL-servers, which
+ * don't support mysql_real_escape_string
+ *
+ * 17 May 2001, Alex Janssen <alex@ynfonatic.de>:
+ * 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 <schuster.sven@gmx.de>:
+ * Added the "port" parameter to specify ports different from 3306
+ *
+ * 12 May 2005, Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * Added reconnecting to lost mysql server.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <arpa/inet.h>
+#include <ulogd/ulogd.h>
+#include <ulogd/conffile.h>
+#include <mysql/mysql.h>
+
+#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);
+}
--- /dev/null
+#
+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
--- /dev/null
+/*
+ * ulogd output target for IP flow analysis
+ *
+ * Mark Huang <mlhuang@cs.princeton.edu>
+ * 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 <stdio.h>
+#include <stdlib.h>
+
+/* va_start() and friends */
+#include <stdarg.h>
+
+/* ispunct() */
+#include <ctype.h>
+
+/* strstr() and friends */
+#include <string.h>
+
+/* dirname() and basename() */
+#include <libgen.h>
+
+/* fork() and wait() */
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+/* fgetpwent() */
+#include <pwd.h>
+
+/* errno and assert() */
+#include <errno.h>
+#include <assert.h>
+
+/* getopt_long() */
+#include <getopt.h>
+
+/* time() and friends */
+#include <time.h>
+#include <sys/time.h>
+
+/* inet_aton() */
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+/* ICMP definitions */
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+
+/* stat() */
+#include <sys/stat.h>
+
+/* pthread_create() */
+#include <pthread.h>
+
+/* flock() */
+#include <sys/file.h>
+
+#include <ulogd/ulogd.h>
+#include <ulogd/conffile.h>
+
+#if !defined(STANDALONE) && HAVE_LIBPROPER
+#include <proper/prop.h>
+#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 <dmalloc.h>
+#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/mysql.h>
+
+/* 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 <linux/jhash.h>
+
+/* 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
--- /dev/null
+#
+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)
--- /dev/null
+/* ulogd_PCAP.c, Version $Revision: 6016 $
+ *
+ * ulogd output target for writing pcap-style files (like tcpdump)
+ *
+ * FIXME: descr.
+ *
+ *
+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <pcap.h>
+#include <ulogd/ulogd.h>
+#include <ulogd/conffile.h>
+
+/*
+ * 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);
+}
--- /dev/null
+#
+
+# 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)
--- /dev/null
+#
+
+# 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)
--- /dev/null
+/* ulogd_PGSQL.c, Version $Revision: 6404 $
+ *
+ * ulogd output plugin for logging to a PGSQL database
+ *
+ * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org>
+ * 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 <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <ulogd/ulogd.h>
+#include <ulogd/conffile.h>
+#include <libpq-fe.h>
+
+
+#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; intaux<PQntuples(result); intaux++) {
+
+ /* replace all underscores with dots */
+ strncpy(buf, PQgetvalue(result, intaux, 0), 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;
+ }
+
+ 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);
+}
--- /dev/null
+# 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)
--- /dev/null
+#
+# 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)
--- /dev/null
+/*
+ * ulogd output plugin for logging to a SQLITE database
+ *
+ * (C) 2005 by Ben La Monica <ben.lamonica@gmail.com>
+ *
+ * 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 <laforge@gnumonks.org>
+ * Alex Janssen <alex@ynfonatic.de>
+ *
+ * You can see benchmarks and an explanation of the testing
+ * at http://www.pojo.us/ulogd/
+ *
+ * 2005-02-09 Harald Welte <laforge@gnumonks.org>:
+ * - port to ulogd-1.20
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <ulogd/ulogd.h>
+#include <ulogd/conffile.h>
+#include <sqlite3.h>
+
+#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);
+}
+
--- /dev/null
+.\" 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 <n> 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 <filename>, --configfile <filename>
+use <filename> 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 <joergland@debian.org>,
+for the Debian GNU/Linux system (but may be used by others).
--- /dev/null
+/* 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 <laforge@gnumonks.org>
+ *
+ * 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 <gandalf@wlug.westbo.se>
+ * - added SIGHUP handler for logfile cycling
+ *
+ * 10 Feb 2002 Alessandro Bono <a.bono@libero.it>
+ * - added support for non-fork mode
+ * - added support for logging to stdout
+ *
+ * 09 Sep 2003 Magnus Boden <sarek@ozaba.cx>
+ * - added support for more flexible multi-section conffile
+ *
+ * 20 Apr 2004 Nicolas Pougetoux <nicolas.pougetoux@edelweb.fr>
+ * - added suppurt for seteuid()
+ */
+
+#define ULOGD_VERSION "1.23"
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <time.h>
+#include <ctype.h>
+#include <signal.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <getopt.h>
+#include <pwd.h>
+#include <grp.h>
+#include <syslog.h>
+#include <libipulog/libipulog.h>
+#include <ulogd/conffile.h>
+#include <ulogd/ulogd.h>
+
+/* 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 "
+ "<laforge@gnumonks.org>\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 "
+ "<laforge@gnumonks.org>\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);
+}
--- /dev/null
+# 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
+
--- /dev/null
+#!/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
--- /dev/null
+/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
+}
--- /dev/null
+#
+# $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 <support@planet-lab.org>
+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 <mef@cs.princeton.edu> 1.22-1gm.planetlab
++ ulogd-1.24-3
+- Do not include postgres & sqlite
+- update to f7 version
+
+* Tue Dec 4 2007 Marc E. Fiuczynski <mef@cs.princeton.edu> 1.22-1gm.planetlab
++ ulogd-1.22-1gm
+- updated to 1.21 release
+- integrated with planetlab build environment
+
+* Wed Feb 16 2005 Harald Welte <laforge@gnumonks.org>
++ ulogd-1.21-1gm
+- updated to 1.21 release
+- separate sqlite3 and pcap sub-pacakges
+
+* Sat Feb 12 2005 Harald Welte <laforge@gnumonks.org>
++ ulogd-1.20-1gm
+- updated to 1.20 release
+- add ulogd.8 manpage
+
+* Fri Nov 05 2004 Mark Huang <mlhuang@cs.princeton.edu> 1.02-3.planetlab
++ planetlab-3_0-rc2
+- service ulogd status: exit with appropriate error code
+
+* Sat Aug 25 2003 Harald Welte <laforge@gnumonks.org>
++ ulogd-1.00-1gm
+- updated to 1.01 release
+- add ulogd.8 manpage
+
+* Wed Mar 05 2003 Harald Welte <laforge@gnumonks.org>
++ ulogd-1.00-1gm
+- updated to 1.00 release
+
+* Mon Sep 24 2001 Harald Welte <laforge@conectiva.com>
++ ulogd-0.97-1cl
+- updatd to 0.97 release (to fix endless-one-packet-loop bug)
+
+* Sun Jun 17 2001 Harald Welte <laforge@conectiva.com>
++ ulogd-0.96-2cl
+- updated to 0.96 final release
+- use ulogd.init from within source tgz
+
+* Sun May 20 2001 Harald Welte <laforge@conectiva.com>
++ ulogd-0.96-1cl
+- Initial conectiva package
+- cleaned up SPEC file
+- created mysql subpackage
+
+* Sun Nov 19 2000 Harald Welte <laforge@gnumonks.org>
+- Initial RPM package for ulogd-0.9.