File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / common / dhcp-eval.5
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:06:54 2012 UTC (11 years, 8 months ago) by misho
Branches: dhcp, MAIN
CVS tags: v4_1_R7p0, v4_1_R7, v4_1_R4, HEAD
dhcp 4.1 r7

    1: .\"	$Id: dhcp-eval.5,v 1.1.1.1 2012/10/09 09:06:54 misho Exp $
    2: .\"
    3: .\" Copyright (c) 2009-2012 by Internet Systems Consortium, Inc. ("ISC")
    4: .\" Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
    5: .\" Copyright (c) 1996-2003 by Internet Software Consortium
    6: .\"
    7: .\" Permission to use, copy, modify, and distribute this software for any
    8: .\" purpose with or without fee is hereby granted, provided that the above
    9: .\" copyright notice and this permission notice appear in all copies.
   10: .\"
   11: .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
   12: .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   13: .\" MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
   14: .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   15: .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   16: .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   17: .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   18: .\"
   19: .\"   Internet Systems Consortium, Inc.
   20: .\"   950 Charter Street
   21: .\"   Redwood City, CA 94063
   22: .\"   <info@isc.org>
   23: .\"   https://www.isc.org/
   24: .\"
   25: .\" This software has been written for Internet Systems Consortium
   26: .\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
   27: .\"
   28: .\" Support and other services are available for ISC products - see
   29: .\" https://www.isc.org for more information or to learn more about ISC.
   30: .\"
   31: .TH dhcp-eval 5
   32: .SH NAME
   33: dhcp-eval - ISC DHCP conditional evaluation
   34: .SH DESCRIPTION
   35: The Internet Systems Consortium DHCP client and server both provide
   36: the ability to perform conditional behavior depending on the contents
   37: of packets they receive.  The syntax for specifying this conditional
   38: behaviour is documented here.
   39: .SH REFERENCE: CONDITIONAL BEHAVIOUR
   40: Conditional behaviour is specified using the if statement and the else
   41: or elsif statements.  A conditional statement can appear anywhere
   42: that a regular statement (e.g., an option statement) can appear, and
   43: can enclose one or more such statements.  A typical conditional
   44: statement in a server might be:
   45: .PP
   46: .nf
   47: if option dhcp-user-class = "accounting" {
   48:   max-lease-time 17600;
   49:   option domain-name "accounting.example.org";
   50:   option domain-name-servers ns1.accounting.example.org,
   51: 			     ns2.accounting.example.org;
   52: } elsif option dhcp-user-class = "sales" {
   53:   max-lease-time 17600;
   54:   option domain-name "sales.example.org";
   55:   option domain-name-servers ns1.sales.example.org,
   56: 			     ns2.sales.example.org;
   57: } elsif option dhcp-user-class = "engineering" {
   58:   max-lease-time 17600;
   59:   option domain-name "engineering.example.org";
   60:   option domain-name-servers ns1.engineering.example.org,
   61: 			     ns2.engineering.example.org;
   62: } else {
   63:   max-lease-time 600;
   64:   option domain-name "misc.example.org";
   65:   option domain-name-servers ns1.misc.example.org,
   66: 			     ns2.misc.example.org;
   67: }
   68: .fi
   69: .PP
   70: On the client side, an example of conditional evaluation might be:
   71: .PP
   72: .nf
   73: # example.org filters DNS at its firewall, so we have to use their DNS
   74: # servers when we connect to their network.  If we are not at
   75: # example.org, prefer our own DNS server.
   76: if not option domain-name = "example.org" {
   77:   prepend domain-name-servers 127.0.0.1;
   78: }
   79: .fi
   80: .PP
   81: The
   82: .B if
   83: statement and the
   84: .B elsif
   85: continuation statement both take boolean expressions as their
   86: arguments.  That is, they take expressions that, when evaluated,
   87: produce a boolean result.  If the expression evaluates to true, then
   88: the statements enclosed in braces following the
   89: .B if
   90: statement are executed, and all subsequent
   91: .B elsif
   92: and
   93: .B else
   94: clauses are skipped.  Otherwise, each subsequent 
   95: .B elsif
   96: clause's expression is checked, until an elsif clause is encountered
   97: whose test evaluates to true.  If such a clause is found, the
   98: statements in braces following it are executed, and then any
   99: subsequent
  100: .B elsif
  101: and
  102: .B else
  103: clauses are skipped.  If all the 
  104: .B if
  105: and
  106: .B elsif
  107: clauses are checked but none
  108: of their expressions evaluate true, then if there is an
  109: .B else
  110: clause, the statements enclosed in braces following the
  111: .B else
  112: are evaluated.  Boolean expressions that evaluate to null are
  113: treated as false in conditionals.
  114: .SH BOOLEAN EXPRESSIONS
  115: The following is the current list of boolean expressions that are
  116: supported by the DHCP distribution.
  117: .PP
  118: .I data-expression-1 \fB=\fR \fIdata-expression-2\fR
  119: .RS 0.25i
  120: .PP
  121: The \fB=\fR operator compares the values of two data expressions,
  122: returning true if they are the same, false if they are not.  If
  123: either the left-hand side or the right-hand side are null, the
  124: result is also null.
  125: .RE
  126: .PP
  127: .I data-expression-1 \fB~=\fR \fIdata-expression-2\fR
  128: .I data-expression-1 \fB~~\fR \fIdata-expression-2\fR
  129: .RS 0.25i
  130: .PP
  131: The \fB~=\fR and \fB~~\fR operators (not available on all systems) perform
  132: extended regex(7) matching of the values of two data expressions, returning
  133: true if \fIdata-expression-1\fR matches against the regular expression
  134: evaluated by \fIdata-expression-2\fR, or false if it does not match or
  135: encounters some error.  If either the left-hand side or the right-hand side
  136: are null or empty strings, the result is also false.  The \fB~~\fR operator
  137: differs from the \fB~=\fR operator in that it is case-insensitive.
  138: .RE
  139: .PP
  140: .I boolean-expression-1 \fBand\fR \fIboolean-expression-2\fR
  141: .PP
  142: .RS 0.25i
  143: The \fBand\fR operator evaluates to true if the boolean expression on
  144: the left-hand side and the boolean expression on the right-hand side
  145: both evaluate to true.  Otherwise, it evaluates to false.  If either
  146: the expression on the left-hand side or the expression on the
  147: right-hand side are null, the result is null.
  148: .RE
  149: .PP
  150: .I boolean-expression-1 \fBor\fR \fIboolean-expression-2\fR
  151: .PP
  152: .RS 0.25i
  153: The \fBor\fR operator evaluates to true if either the boolean
  154: expression on the left-hand side or the boolean expression on the
  155: right-hand side evaluate to true.  Otherwise, it evaluates to false.
  156: If either the expression on the left-hand side or the expression on
  157: the right-hand side are null, the result is null.
  158: .RE
  159: .PP
  160: .B not \fIboolean-expression
  161: .PP
  162: .RS 0.25i
  163: The \fBnot\fR operator evaluates to true if \fIboolean-expression\fR
  164: evaluates to false, and returns false if \fIboolean-expression\fR evaluates
  165: to true.  If \fIboolean-expression\fR evaluates to null, the result
  166: is also null.
  167: .RE
  168: .PP
  169: .B exists \fIoption-name\fR
  170: .PP
  171: .RS 0.25i
  172: The \fBexists\fR expression returns true if the specified option
  173: exists in the incoming DHCP packet being processed.
  174: .RE
  175: .B known
  176: .PP
  177: .RS 0.25i
  178: The \fBknown\fR expression returns true if the client whose request is
  179: currently being processed is known - that is, if there's a host
  180: declaration for it.
  181: .RE
  182: .B static
  183: .PP
  184: .RS 0.25i
  185: The \fBstatic\fR expression returns true if the lease assigned to the
  186: client whose request is currently being processed is derived from a static
  187: address assignment.
  188: .RE
  189: .SH DATA EXPRESSIONS
  190: Several of the boolean expressions above depend on the results of
  191: evaluating data expressions.  A list of these expressions is provided
  192: here.
  193: .PP
  194: .B substring (\fIdata-expr\fB, \fIoffset\fB, \fIlength\fB)\fR
  195: .PP
  196: .RS 0.25i
  197: The \fBsubstring\fR operator evaluates the data expression and returns
  198: the substring of the result of that evaluation that starts
  199: \fIoffset\fR bytes from the beginning, continuing for \fIlength\fR
  200: bytes.  \fIOffset\fR and \fIlength\fR are both numeric expressions.
  201: If \fIdata-expr\fR, \fIoffset\fR or \fIlength\fR evaluate to null,
  202: then the result is also null.  If \fIoffset\fR is greater than or
  203: equal to the length of the evaluated data, then a zero-length data
  204: string is returned.  If \fIlength\fI is greater then the remaining
  205: length of the evaluated data after \fIoffset\fR, then a data string
  206: containing all data from \fIoffset\fR to the end of the evaluated data
  207: is returned.
  208: .RE
  209: .PP
  210: .B suffix (\fIdata-expr\fB, \fIlength\fB)\fR
  211: .PP
  212: .RS 0.25i
  213: The \fBsuffix\fR operator evaluates \fIdata-expr\fR and returns the
  214: last \fIlength\fR bytes of the result of that evaluation.  \fILength\fR
  215: is a numeric expression.  If \fIdata-expr\fR or \fIlength\fR evaluate
  216: to null, then the result is also null.  If \fIsuffix\fR evaluates to a
  217: number greater than the length of the evaluated data, then the
  218: evaluated data is returned.
  219: .RE
  220: .PP
  221: .B lcase (\fIdata-expr\fB)\fR
  222: .PP
  223: .RS 0.25i
  224: The \fBlcase\fR function returns the result of evaluating
  225: \fIdata-expr\fR converted to lower case.  If \fIdata-expr\fR evaluates
  226: to null, then the result is also null.
  227: .RE
  228: .PP
  229: .B ucase (\fIdata-expr\fB)\fR
  230: .PP
  231: .RS 0.25i
  232: The \fBucase\fR function returns the result of evaluating
  233: \fIdata-expr\fR converted to upper case.  If \fIdata-expr\fR evaluates
  234: to null, then the result is also null.
  235: .RE
  236: .PP
  237: .B option \fIoption-name\fR
  238: .PP
  239: .RS 0.25i
  240: The \fBoption\fR operator returns the contents of the specified option in
  241: the packet to which the server is responding.
  242: .RE
  243: .PP
  244: .B config-option \fIoption-name\fR
  245: .PP
  246: .RS 0.25i
  247: The \fBconfig-option\fR operator returns the value for the specified option
  248: that the DHCP client or server has been configured to send.
  249: .RE
  250: .PP
  251: .B hardware
  252: .PP
  253: .RS 0.25i
  254: The \fBhardware\fR operator returns a data string whose first element
  255: is the type of network interface indicated in packet being considered,
  256: and whose subsequent elements are client's link-layer address.  If
  257: there is no packet, or if the RFC2131 \fIhlen\fR field is invalid,
  258: then the result is null.  Hardware types include ethernet (1),
  259: token-ring (6), and fddi (8).  Hardware types are specified by the
  260: IETF, and details on how the type numbers are defined can be found in
  261: RFC2131 (in the ISC DHCP distribution, this is included in the doc/
  262: subdirectory).
  263: .RE
  264: .PP
  265: .B packet (\fIoffset\fB, \fIlength\fB)\fR
  266: .PP
  267: .RS 0.25i
  268: The \fBpacket\fR operator returns the specified portion of the packet
  269: being considered, or null in contexts where no packet is being
  270: considered.  \fIOffset\fR and \fIlength\fR are applied to the
  271: contents packet as in the \fBsubstring\fR operator.
  272: .RE
  273: .PP
  274: .I string
  275: .PP
  276: .RS 0.25i
  277: A string, enclosed in quotes, may be specified as a data expression,
  278: and returns the text between the quotes, encoded in ASCII.  The
  279: backslash ('\\') character is treated specially, as in C programming: '\\t'
  280: means TAB, '\\r' means carriage return, '\\n' means newline, and '\\b' means
  281: bell.  Any octal value can be specified with '\\nnn', where nnn is any
  282: positive octal number less than 0400.  Any hexadecimal value can be
  283: specified with '\\xnn', where nn is any positive hexadecimal number less
  284: than or equal to 0xff.
  285: .RE
  286: .PP
  287: .I colon-separated hexadecimal list
  288: .PP
  289: .RS 0.25i
  290: A list of hexadecimal octet values, separated by colons, may be
  291: specified as a data expression.
  292: .RE
  293: .PP
  294: .B concat (\fIdata-expr1\fB, ..., \fIdata-exprN\fB)\fR
  295: .RS 0.25i
  296: The expressions are evaluated, and the results of each evaluation are
  297: concatenated in the sequence that the subexpressions are listed.  If
  298: any subexpression evaluates to null, the result of the concatenation
  299: is null.
  300: .RE
  301: .PP
  302: .B reverse (\fInumeric-expr1\fB, \fIdata-expr2\fB)\fR
  303: .RS 0.25i
  304: The two expressions are evaluated, and then the result of evaluating
  305: the data expression is reversed in place, using hunks of the size
  306: specified in the numeric expression.  For example, if the numeric
  307: expression evaluates to four, and the data expression evaluates to
  308: twelve bytes of data, then the reverse expression will evaluate to
  309: twelve bytes of data, consisting of the last four bytes of the the
  310: input data, followed by the middle four bytes, followed by the first
  311: four bytes.
  312: .RE
  313: .PP
  314: .B leased-address
  315: .RS 0.25i
  316: In any context where the client whose request is being processed has
  317: been assigned an IP address, this data expression returns that IP
  318: address.  In any context where the client whose request is being
  319: processed has not been assigned an ip address, if this data expression
  320: is found in executable statements executed on that client's behalf,
  321: a log message indicating "there is no lease associated with this client"
  322: is syslogged to the debug level (this is considered dhcpd.conf debugging
  323: information).
  324: .RE
  325: .PP
  326: .B binary-to-ascii (\fInumeric-expr1\fB, \fInumeric-expr2\fB,
  327: .B \fIdata-expr1\fB,\fR \fIdata-expr2\fB)\fR
  328: .RS 0.25i
  329: Converts the result of evaluating data-expr2 into a text string
  330: containing one number for each element of the result of evaluating
  331: data-expr2.  Each number is separated from the other by the result of
  332: evaluating data-expr1.  The result of evaluating numeric-expr1
  333: specifies the base (2 through 16) into which the numbers should be
  334: converted.  The result of evaluating numeric-expr2 specifies the
  335: width in bits of each number, which may be either 8, 16 or 32.
  336: .PP
  337: As an example of the preceding three types of expressions, to produce
  338: the name of a PTR record for the IP address being assigned to a
  339: client, one could write the following expression:
  340: .RE
  341: .PP
  342: .nf
  343:         concat (binary-to-ascii (10, 8, ".",
  344:                                  reverse (1, leased-address)),
  345:                 ".in-addr.arpa.");
  346: 
  347: .fi
  348: .RE
  349: .PP
  350: .B encode-int (\fInumeric-expr\fB, \fIwidth\fB)\fR
  351: .RS 0.25i
  352: Numeric-expr is evaluated and encoded as a data string of the
  353: specified width, in network byte order (most significant byte first).
  354: If the numeric expression evaluates to the null value, the result is
  355: also null.
  356: .RE
  357: .PP
  358: .B pick-first-value (\fIdata-expr1\fR [ ... \fIexpr\fRn ] \fB)\fR
  359: .RS 0.25i
  360: The pick-first-value function takes any number of data expressions as
  361: its arguments.  Each expression is evaluated, starting with the first
  362: in the list, until an expression is found that does not evaluate to a
  363: null value.  That expression is returned, and none of the subsequent
  364: expressions are evaluated.  If all expressions evaluate to a null
  365: value, the null value is returned.
  366: .RE
  367: .PP
  368: .B host-decl-name
  369: .RS 0.25i
  370: The host-decl-name function returns the name of the host declaration
  371: that matched the client whose request is currently being processed, if
  372: any.  If no host declaration matched, the result is the null value.
  373: .RE
  374: .SH NUMERIC EXPRESSIONS
  375: Numeric expressions are expressions that evaluate to an integer.  In
  376: general, the maximum size of such an integer should not be assumed to
  377: be representable in fewer than 32 bits, but the precision of such
  378: integers may be more than 32 bits.
  379: .PP
  380: .B extract-int (\fIdata-expr\fB, \fIwidth\fB)\fR
  381: .PP
  382: .RS 0.25i
  383: The \fBextract-int\fR operator extracts an integer value in network
  384: byte order from the result of evaluating the specified data
  385: expression.  Width is the width in bits of the integer to extract.
  386: Currently, the only supported widths are 8, 16 and 32.  If the
  387: evaluation of the data expression doesn't provide sufficient bits to
  388: extract an integer of the specified size, the null value is returned.
  389: .RE
  390: .PP
  391: .B lease-time
  392: .PP
  393: .RS 0.25i
  394: The duration of the current lease - that is, the difference between
  395: the current time and the time that the lease expires.
  396: .RE
  397: .PP
  398: .I number
  399: .PP
  400: .RS 0.25i
  401: Any number between zero and the maximum representable size may be
  402: specified as a numeric expression.
  403: .RE
  404: .PP
  405: .B client-state
  406: .PP
  407: .RS 0.25i
  408: The current state of the client instance being processed.  This is
  409: only useful in DHCP client configuration files.  Possible values are:
  410: .TP 2
  411: .I \(bu
  412: Booting - DHCP client is in the INIT state, and does not yet have an
  413: IP address.  The next message transmitted will be a DHCPDISCOVER,
  414: which will be broadcast.
  415: .TP
  416: .I \(bu
  417: Reboot - DHCP client is in the INIT-REBOOT state.  It has an IP
  418: address, but is not yet using it.  The next message to be transmitted
  419: will be a DHCPREQUEST, which will be broadcast.  If no response is
  420: heard, the client will bind to its address and move to the BOUND state.
  421: .TP
  422: .I \(bu
  423: Select - DHCP client is in the SELECTING state - it has received at
  424: least one DHCPOFFER message, but is waiting to see if it may receive
  425: other DHCPOFFER messages from other servers.  No messages are sent in
  426: the SELECTING state.
  427: .TP
  428: .I \(bu
  429: Request - DHCP client is in the REQUESTING state - it has received at
  430: least one DHCPOFFER message, and has chosen which one it will
  431: request.  The next message to be sent will be a DHCPREQUEST message,
  432: which will be broadcast.
  433: .TP
  434: .I \(bu
  435: Bound - DHCP client is in the BOUND state - it has an IP address.  No
  436: messages are transmitted in this state.
  437: .TP
  438: .I \(bu
  439: Renew - DHCP client is in the RENEWING state - it has an IP address,
  440: and is trying to contact the server to renew it.  The next message to
  441: be sent will be a DHCPREQUEST message, which will be unicast directly
  442: to the server.
  443: .TP
  444: .I \(bu
  445: Rebind - DHCP client is in the REBINDING state - it has an IP address,
  446: and is trying to contact any server to renew it.  The next message to
  447: be sent will be a DHCPREQUEST, which will be broadcast.
  448: .RE
  449: .SH REFERENCE: ACTION EXPRESSIONS
  450: .PP
  451: .B log (\fIpriority\fB, \fIdata-expr\fB)\fR
  452: .RS 0.25i
  453: .PP
  454: Logging statements may be used to send information to the standard logging
  455: channels.  A logging statement includes an optional priority (\fBfatal\fR,
  456: \fBerror\fR, \fBinfo\fR, or \fBdebug\fR), and a data expression.
  457: .PP
  458: Logging statements take only a single data expression argument, so if you
  459: want to output multiple data values, you will need to use the \fBconcat\fR
  460: operator to concatenate them.
  461: .RE
  462: .PP
  463: .B execute (\fIcommand-path\fB [, \fIdata-expr1\fB, ... \fIdata-exprN\fB]);\fR
  464: .RS 0.25i
  465: .PP
  466: The \fBexecute\fR statement runs an external command.  The first argument
  467: is a string literal containing the name or path of the command to run.
  468: The other arguments, if present, are either string literals or data-
  469: expressions which evaluate to text strings, to be passed as command-line
  470: arguments to the command.
  471: .PP
  472: \fBexecute\fR is synchronous; the program will block until the external
  473: command being run has finished.  Please note that lengthy program
  474: execution (for example, in an "on commit" in dhcpd.conf) may result in
  475: bad performance and timeouts.  Only external applications with very short
  476: execution times are suitable for use.
  477: .PP
  478: Passing user-supplied data to an external application might be dangerous.
  479: Make sure the external application checks input buffers for validity.
  480: Non-printable ASCII characters will be converted into dhcpd.conf language
  481: octal escapes ("\\nnn"), make sure your external command handles them as
  482: such.
  483: .PP
  484: It is possible to use the execute statement in any context, not only
  485: on events.  If you put it in a regular scope in the configuration file
  486: you will execute that command every time a scope is evaluated.
  487: .RE
  488: .SH REFERENCE: DYNAMIC DNS UPDATES
  489: .PP
  490: The DHCP client and server have the ability to dynamically update the
  491: Domain Name System.  Within the configuration files, you can define
  492: how you want the Domain Name System to be updated.  These updates are
  493: RFC 2136 compliant so any DNS server supporting RFC 2136 should be
  494: able to accept updates from the DHCP server.
  495: .SH SECURITY
  496: Support for TSIG and DNSSEC is not yet available.  When you set your
  497: DNS server up to allow updates from the DHCP server or client, you may
  498: be exposing it to unauthorized updates.  To avoid this, the best you
  499: can do right now is to use IP address-based packet filtering to
  500: prevent unauthorized hosts from submitting update requests.
  501: Obviously, there is currently no way to provide security for client
  502: updates - this will require TSIG or DNSSEC, neither of which is yet
  503: available in the DHCP distribution.
  504: .PP
  505: Dynamic DNS (DDNS) updates are performed by using the \fBdns-update\fR
  506: expression.  The \fBdns-update\fR expression is a boolean expression
  507: that takes four parameters.  If the update succeeds, the result is
  508: true.  If it fails, the result is false.  The four parameters that the
  509: are the resource record type (RR), the left hand side of the RR, the
  510: right hand side of the RR and the ttl that should be applied to the
  511: record.  The simplest example of the use of the function can be found
  512: in the reference section of the dhcpd.conf file, where events are
  513: described.  In this example several statements are being used to make
  514: the arguments to the \fBdns-update\fR.
  515: .PP
  516: In the example, the first argument to the first \f\Bdns-update\fR
  517: expression is a data expression that evaluates to the A RR type.  The
  518: second argument is constructed by concatenating the DHCP host-name
  519: option with a text string containing the local domain, in this case
  520: "ssd.example.net".  The third argument is constructed by converting
  521: the address the client has been assigned from a 32-bit number into an
  522: ascii string with each byte separated by a ".".  The fourth argument,
  523: the TTL, specifies the amount of time remaining in the lease (note
  524: that this isn't really correct, since the DNS server will pass this
  525: TTL out whenever a request comes in, even if that is only a few
  526: seconds before the lease expires).
  527: .PP
  528: If the first \fBdns-update\fR statement succeeds, it is followed up
  529: with a second update to install a PTR RR.  The installation of a PTR
  530: record is similar to installing an A RR except that the left hand side
  531: of the record is the leased address, reversed, with ".in-addr.arpa"
  532: concatenated.  The right hand side is the fully qualified domain name
  533: of the client to which the address is being leased.
  534: .SH SEE ALSO
  535: dhcpd.conf(5), dhcpd.leases(5), dhclient.conf(5), dhcp-options(5), dhcpd(8),
  536: dhclient(8), RFC2132, RFC2131.
  537: .SH AUTHOR
  538: The Internet Systems Consortium DHCP Distribution was written by Ted
  539: Lemon under a contract with Vixie Labs.  Funding for
  540: this project was provided through Internet Systems Consortium.
  541: Information about Internet Systems Consortium can be found at
  542: .B https://www.isc.org.

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>