Annotation of embedaddon/dhcp/doc/api+protocol, revision 1.1
1.1 ! misho 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>