File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / doc / api+protocol
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, 11 months ago) by misho
Branches: dhcp, MAIN
CVS tags: v4_1_R7p0, v4_1_R7, v4_1_R4, HEAD
dhcp 4.1 r7

    1: This file documents the protocol that the ISC DHCP server and ISC
    2: Object Management clients (clients that use the ISC Object Management
    3: API) speak between one another.
    4: 
    5: Protocol:
    6: 
    7: All multi-byte numbers are represented in network byte order.
    8: 
    9: On startup, each side sends a status message indicating what version
   10: of the protocol they are speaking.   The status message looks like
   11: this:
   12: 
   13: +---------+---------+
   14: | version | hlength |
   15: +---------+---------+
   16: 
   17: version - a 32-bit fixed-point number with the decimal point between
   18: 	  the third and second decimal digits from the left,
   19: 	  representing the version of the protocol.   The current
   20: 	  protocol version is 1.00.   If the field were considered as
   21: 	  a 32-bit integer, this would correspond to a value of 100
   22: 	  decimal, or 0x64.
   23: 
   24: hlength - a 32-bit integer representing the length of the fixed-length
   25: 	  header in subsequent messages.   This is normally 56, but
   26: 	  can be changed to a value larger than 56 by either side
   27: 	  without upgrading the revision number.
   28: 
   29: 
   30: The startup message is not authenticated.   Either side may reject the
   31: other side's startup message as invalid by simply closing the
   32: connection.   The only fixed part of the startup message is the
   33: version number - future versions may delete hlength, or add further
   34: startup information.
   35: 
   36: Following the startup message, all messages have the same format.
   37: Currently, the format includes a fixed-length header (the length in
   38: hlength, above)
   39: 
   40: +--------+----+--------+----+-----+---------+------------+------------+-----+
   41: | authid | op | handle | id | rid | authlen | msg values | obj values | sig |
   42: +--------+----+--------+----+-----+---------+------------+------------+-----+
   43: 
   44: The fixed-length header consists of:
   45: 
   46: authid = a 32-bit authenticator handle.
   47: 	For an original message (one not in response to some other
   48: 	message), this will be chosen by the originator.   For a
   49: 	message in response to another message, the authenticator for
   50: 	that message is used, except if the response is an error
   51: 	message indicating that the authenticator used was unknown,
   52: 	in which case the null authenticator is used.   Messages that
   53: 	are generated as the result of a notify registration use the
   54: 	authenticator used in the original notify registration.
   55: 	The authenticator itself is generated by having one side of
   56: 	the connection send an object of type "authenticator" to the
   57: 	other side with values that indicate what kind of
   58: 	authentication mechanism to use and what key to use.   The two
   59: 	most likely things here are a Kerberos V principal name or the
   60: 	name of a shared secret that can be used to calculate an MD5
   61: 	hash.   The mechanism for doing this has yet to be finalized.
   62: 	If authid is zero, the message is not authenticated.
   63: 
   64: op = 32-bit opcode, one of:
   65: 	open = 1
   66: 	refresh = 2
   67: 	update = 3
   68: 	notify = 4
   69: 	error = 5
   70: 	delete = 6
   71: handle = 32-bit object handle
   72: 	A handle on the object being opened, created, refreshed or
   73: 	updated.   If no handle is yet available (e.g., with open and
   74: 	new), then the value zero is sent.
   75: id = 32-bit transaction id of the message - a monotonically increasing
   76:      number that starts with some randomly chosen number at the
   77:      beginning of the life of the connection.   The value should never
   78:      be zero.
   79: rid = 32-bit transaction ID of the message to which this message is a
   80:       response, or zero if this message is not in response to a
   81:       message from the other side.
   82: 
   83: authlen = a 32-bit number representing the length of the authenticator
   84: 
   85: msg values = a series of name+value pairs, specific to this message.
   86: 	 Each name+value pair starts with a 16-bit name length,
   87: 	 followed by that many bytes of name, followed by a 32-bit
   88: 	 value length, followed by that many bytes of value.   If the
   89: 	 length is zero, this is a value of the blank string.   If the
   90: 	 length is all ones (2^32-1), then there is no value - for an
   91: 	 update, this means the value for this name and the name
   92: 	 itself should be deleted from the object, which may or may
   93: 	 not be possible.   The list of name/value pairs ends with a
   94: 	 zero-length name, which is not followed by a value
   95: 	 length/value pair.
   96: 
   97: obj values = a series of name+value pairs, as above, specific to the
   98: 	object being created, updated or refreshed.
   99: 
  100: signature = authlen bytes of data signing the message.   The signature
  101: 	    algorithm is a property of the authenticator handle.
  102: 
  103: Message types:
  104: 
  105: 1: open
  106:    relevant input values:
  107: 	object-type = the name of the type of object
  108: 	open:create = boolean - create the object if it doesn't yet exist
  109: 	open:exclusive = boolean - don't open the object if it does exist
  110: 	open:update = boolean - update the object with included values
  111: 		      if it matches.
  112: 	the handle should always be the null handle
  113: 
  114:    The input value must also contain key information for the type of
  115:    object being searched that uniquely identifies an object, or search
  116:    information that matches only one object.  Each object has a key
  117:    specification (a key is something that uniquely identifies an
  118:    object), so see the key specification for that object to see
  119:    what to send here.   An open message with the create flag set must
  120:    specify a key, and not merely matching criteria.   Some objects may
  121:    allow more than one key, and it may be that the union of those keys
  122:    is required to uniquely identify the object, or it may be that any
  123:    one such key will uniquely identify the object.   The documentation
  124:    for the type of object will specify this.
  125: 
  126:    An open message will result in an immediate response message whose
  127:    opcode will either be "error" or "update".   The error message may
  128:    include an error:reason value containing a text string explaining
  129:    the error, and will always include an error:code value which will
  130:    be the numeric error code for what went wrong.   Possible error
  131:    codes are:
  132: 
  133: 	not found - no such object exists
  134: 	already exists - object already exists, and exclusive flag was
  135: 			 set.
  136: 	not unique - more than one object matching the specification
  137: 		     exists.
  138: 	permission denied - the authenticator ID specified does not
  139: 			    have authorization to access this object,
  140: 			    or if the update flag was specified, to
  141: 			    update the object.
  142: 
  143:    If the response is an update message, the update message will
  144:    include the object handle and all of the name/value pairs
  145:    associated with that object.
  146: 
  147: 2: refresh
  148: 
  149:    no input values except the handle need be specified.   The null
  150:    handle may not be specified.   If the handle is valid, and the
  151:    authenticator ID specified has permission to examine the object,
  152:    then an update message will be sent for that object.   Otherwise,
  153:    one of the following errors will be sent:
  154: 
  155: 	invalid handle - the handle does not refer to a known object
  156: 	permisson denied - the handle refers to an object that the
  157: 			   requestor does not have permission to
  158: 			   examine. 
  159: 
  160: 3: update
  161: 
  162:    Requests that the contents of the specified object be updated with
  163:    the values included.   Values that are not specified are not
  164:    updated.   The response will be either an error message or an
  165:    update-ok message.   If rid is nonzero, no response will be
  166:    generated, even if there was an error.   Possible errors include:
  167: 
  168: 	invalid handle - no such object was found
  169: 	permission denied - the handle refers to an object that the
  170: 			    requestor does not have permission to
  171: 			    modify.
  172: 	not confirmed - the update could not be committed due to some
  173: 			kind of resource problem, for example
  174: 			insufficient memory or a disk failure.
  175: 
  176: 4: notify
  177: 
  178:    Requests that whenever the object with the specified handle is
  179:    modified, an update be sent.   If there is something wrong with the
  180:    request, an error message will be returned immediately.
  181:    Otherwise, whenever a change is made to the object, an update
  182:    message will be sent containing whatever changes were made (or
  183:    possibly all the values associated with the object, depending on
  184:    the implementation).   Possible errors:
  185: 
  186: 	invalid handle
  187: 	permission denied - the handle refers to an object that the
  188: 			    requestor does not have permission to
  189: 			    examine.
  190: 	not supported - the object implementation does not support
  191: 			notifications
  192: 
  193: 5: status
  194: 
  195:    Sends a status code in response to a message.  Always sent in
  196:    response to a message sent by the other side.  There should never
  197:    be a response to this message.
  198: 
  199: 6: delete
  200: 
  201:    Deletes the specified object.   Response will be either request-ok,
  202:    or error.   Possible errors include:
  203: 
  204: 	invalid handle - no such object was found
  205: 	permission denied - the handle refers to an object that the
  206: 			    requestor does not have permission to
  207: 			    modify.
  208: 	not confirmed - the deletion could not be committed due to
  209: 			some kind of resource problem, for example
  210: 			insufficient memory or a disk failure.
  211: 
  212: 7: notify-cancel
  213: 
  214:    Like notify, but requests that an existing notification be cancelled.
  215: 
  216: 8: notify-cancelled
  217: 
  218:    Indicates that because of a local change, a notification that had
  219:    been registered can no longer be performed.   This could be as a
  220:    result of the permissions on a object changing, or an object being
  221:    deleted.   There should never be a response to this message.
  222: 
  223: internals:
  224: 
  225: Both client and server use same protocol and infrastructure.   There
  226: are many object types, each of which is stored in a registry.
  227: Objects whose type is not recognized can either be handled by the
  228: generic object type, which is registered with the type "*".   If no
  229: generic object type is registered, then objects with unknown types are
  230: simply not supported.   On the client, there are probably no special
  231: object handlers (although this is by no means forbidden).   On the
  232: server, probably everything is a special object.
  233: 
  234: Each object type has the following methods:
  235: 
  236: 
  237: 
  238: 
  239: dhcpctl_status dhcpctl_connect (dhcpctl_handle *connection,
  240: 				char *server_name, int port,
  241: 				dhcpctl_handle *authinfo)
  242: 	synchronous
  243: 	returns nonzero status code if it didn't connect, zero otherwise
  244: 	stores connection handle through connection, which can be used
  245: 	for subsequent access to the specified server. 
  246: 	server_name is the name of the server, and port is the TCP
  247: 	port on which it is listening.
  248: 	authinfo is the handle to an object containing authentication
  249: 	information.
  250: 
  251: dhcpctl_status dhcpctl_open_object (dhcpctl_handle h,
  252: 				    dhcpctl_handle connection,
  253: 				    int flags)
  254: 	asynchronous - just queues the request
  255: 	returns nonzero status code if open couldn't be queued
  256: 	returns zero if open was queued
  257: 	h is a handle to an object created by dhcpctl_new_object
  258: 	connection is a connection to a DHCP server
  259: 	flags include:
  260: 	   DHCPCTL_CREATE - if the object doesn't exist, create it
  261: 	   DHCPCTL_UPDATE - update the object on the server using the
  262: 			    attached parameters 
  263: 	   DHCPCTL_EXCL - error if the object exists and DHCPCTL_CREATE
  264: 			  was also specified
  265: 
  266: dhcpctl_status dhcpctl_new_object (dhcpctl_handle *h,
  267: 				   dhcpctl_handle connection,
  268: 				   char *object_type)
  269: 	synchronous - creates a local handle for a host entry.
  270: 	returns nonzero status code if the local host entry couldn't
  271: 	be created
  272: 	stores handle to host through h if successful, and returns zero.
  273: 	object_type is a pointer to a NUL-terminated string containing
  274: 	the ascii name of the type of object being accessed - e.g., "host"
  275: 
  276: dhcpctl_status dhcpctl_set_callback (dhcpctl_handle h, void *data,
  277: 				     void (*callback) (dhcpctl_handle,
  278: 						       dhcpctl_status, void *))
  279: 	synchronous, with asynchronous aftereffect
  280: 	handle is some object upon which some kind of process has been
  281: 	started - e.g., an open, an update or a refresh.
  282: 	data is an anonymous pointer containing some information that
  283: 	the callback will use to figure out what event completed.
  284: 	return value of 0 means callback was successfully set, a nonzero
  285: 	status code is returned otherwise.
  286: 	Upon completion of whatever task is in process, the callback
  287: 	will be passed the handle to the object, a status code
  288: 	indicating what happened, and the anonymous pointer passed to 
  289: 
  290: dhcpctl_status dhcpctl_wait_for_completion (dhcpctl_handle h,
  291: 					    dhcpctl_status *s)
  292: 	synchronous
  293: 	returns zero if the callback completes, a nonzero status if
  294: 	there was some problem relating to the wait operation.   The
  295: 	status of the queued request will be stored through s, and
  296: 	will also be either zero for success or nonzero for some kind
  297: 	of failure.    Never returns until completion or until the
  298: 	connection to the server is lost.   This performs the same
  299: 	function as dhcpctl_set_callback and the subsequent callback,
  300: 	for programs that want to do inline execution instead of using
  301: 	callbacks.
  302: 
  303: dhcpctl_status dhcpctl_get_value (data_string *result,
  304: 				  dhcpctl_handle h, char *value_name)
  305: 	synchronous
  306: 	returns zero if the call succeeded, a nonzero status code if
  307: 	it didn't. 
  308: 	result is the address of an empty data string (initialized
  309: 	with bzero or cleared with data_string_forget).   On
  310: 	successful completion, the addressed data string will contain
  311: 	the value that was fetched.
  312: 	dhcpctl_handle refers to some dhcpctl item
  313: 	value_name refers to some value related to that item - e.g.,
  314: 	for a handle associated with a completed host lookup, value
  315: 	could be one of "hardware-address", "dhcp-client-identifier",
  316: 	"known" or "client-hostname".
  317: 
  318: dhcpctl_status dhcpctl_get_boolean (int *result,
  319: 				    dhcpctl_handle h, char *value_name)
  320: 	like dhcpctl_get_value, but more convenient for boolean
  321: 	values, since no data_string needs to be dealt with.
  322: 
  323: dhcpctl_status dhcpctl_set_value (dhcpctl_handle h, data_string value,
  324: 				  char *value_name)
  325: 	Sets a value on an object referred to by a dhcpctl_handle.
  326: 	The opposite of dhcpctl_get_value.   Does not update the
  327: 	server - just sets the value on the handle.
  328: 
  329: dhcpctl_status dhcpctl_set_string_value (dhcpctl_handle h, char *value,
  330: 					 char *value_name)
  331: 	Sets a NUL-terminated ASCII value on an object referred to by
  332: 	a dhcpctl_handle.   like dhcpctl_set_value, but saves the
  333: 	trouble of creating a data_string for a NUL-terminated string.
  334: 	Does not update the server - just sets the value on the handle.
  335: 
  336: dhcpctl_status dhcpctl_set_boolean (dhcpctl_handle h, int value,
  337: 				    char *value_name)
  338: 	Sets a boolean value on an object - like dhcpctl_set_value,
  339: 	only more convenient for booleans.
  340: 
  341: dhcpctl_status dhcpctl_object_update (dhcpctl_handle h)
  342: 	Queues an update on the object referenced by the handle (there
  343: 	can't be any other work in progress on the handle).   An
  344: 	update means local parameters will be sent to the server.
  345: 
  346: dhcpctl_status dhcpctl_object_refresh (dhcpctl_handle h)
  347: 	Queues an update on the object referenced by the handle (there
  348: 	can't be any other work in progress on the handle).   An
  349: 	update means local parameters will be sent to the server.
  350: 
  351: dhcpctl_status dhcpctl_object_delete (dhcpctl_handle h)
  352: 	Queues a delete of the object referenced by the handle (there
  353: 	can't be any other work in progress on the handle).   A
  354: 	delete means that the object will be permanently deleted on
  355: 	the remote end, assuming the remote end supports object
  356: 	persistence.
  357: 
  358: So a sample program that would update a host declaration would look
  359: something like this:
  360: 
  361: 	/* Create a local object into which to store authentication
  362: 	   information. */
  363: 	if ((status = dhcpctl_new_object (&auth, dhcpctl_null_handle,
  364: 					  "authentication-information")))
  365: 		dhcpctl_error ("Can't create authentication information: %m");
  366: 
  367: 	/* Set up the authenticator with an algorithm type, user name and
  368: 	   password. */
  369: 	if ((status = dhcpctl_set_string_value (&auth, "mellon", "username")))
  370: 		dhcpctl_error ("Can't set username: %m", status);
  371: 	if ((status = dhcpctl_set_string_value (&auth, "three blind mice",
  372: 						"password")))
  373: 		dhcpctl_error ("Can't set password: %m", status);
  374: 	if ((status = dhcpctl_set_string_value (&auth, "md5-hash",
  375: 						"algorithm")))
  376: 		dhcpctl_error ("Can't set authentication algorithm: %m.",
  377: 			       status);
  378: 
  379: 	/* Connect to the server. */
  380: 	if ((status = dhcpctl_connect (&c, "dhcp.server.com", 612, &auth)))
  381: 
  382: 		dhcpctl_error ("Can't connect to dhcp.server.com: %m",
  383: 			       status);
  384: 
  385: 	/* Create a host object. */
  386: 	if ((status = dhcpctl_new_object (&hp, c, "host")))
  387: 		dhcpctl_error ("Host create failed: %m", status);
  388: 
  389: 	/* Create a data_string to contain the host's client
  390: 	   identifier, and set it. */
  391: 	if ((status =
  392: 	     data_string_create_from_hex (&client_id,
  393: 					  "1:08:00:2b:34:1a:c3")))
  394: 		dhcpctl_error ("Can't create client identifier: %m");
  395: 	if ((status = dhcpctl_set_value (hp, client_id,
  396: 					 "dhcp-client-identifier")))
  397: 		dhcpctl_error ("Host client identifier set failed.");
  398: 	/* Set the known flag to 1. */
  399: 	if ((status = dhcpctl_set_boolean (hp, 1, "known")))
  400: 		dhcpctl_error ("Host known set failed.");
  401: 
  402: 	/* Open an existing host object that matches the client identifier,
  403: 	   and update it from the local context, or if no host entry
  404: 	   yet exists matching the identifier, create one and
  405: 	   initialize it. */
  406: 	if ((status = dhcpctl_open_object (&hp, c,
  407: 					   DHCPCTL_CREATE | DHCPCTL_UPDATE)))
  408: 		dhcpctl_error ("Can't open host: %m", status);
  409: 
  410: 	/* Wait for the process to complete, check status. */
  411: 	if ((status = dhcpctl_wait_for_completion (hp, &wait_status)))
  412: 		dhcpctl_error ("Host create/lookup wait failed: %m", status);
  413: 	if (waitstatus)
  414: 		dhcpctl_error ("Host create/lookup failed: %m", status);
  415: 
  416: The API is a bit complicated, for a couple of reasons.   I want to
  417: make it general, so that there aren't a bazillion functions to call,
  418: one for each data type.   I want it to be thread-safe, which is why
  419: each function returns a status and the error printer requires a status
  420: code for input.   I want it to be possible to make it asynchronous, so
  421: that it can work in tandem with, for example, an X toolkit.   If
  422: you're just writing a simple update cgi program, you probably won't
  423: want to bother to use the asynchronous callbacks, and indeed the above
  424: example doesn't.
  425: 
  426: I glossed over data strings above - basically, they're objects with a
  427: pointer to a reference-counted buffer structure, an offset into that
  428: buffer, and a length.   These are used within the DHCP server, so you
  429: can get an idea of how they work - basically, they're a convenient and
  430: efficient way to store a string with a length such that substrings can
  431: easily be taken and such that more than one user at a time can have a
  432: pointer to the string.
  433: 
  434: I will also probably add locking primitives, so that you can get the
  435: value of something and be sure that some other updator process won't
  436: modify it while you have the lock.

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