omapi(3)

πŸ“¦
version 4.4.3.P1 Β· 3 versions
, in arch rolling, debian bookworm, debian trixie, fedora 43, fedora 44, ubuntu noble, ubuntu resolute

πŸ’… OMAPI β€” Object Management Application Programming Interface ✨

okay so bestie, welcome to the omapi(3) page from the Library Functions Manual 🌸 this is where you learn how to talk to a server from your very own code, and honestly? it's giving main character energy. let's go πŸ’–


🌈 NAME 🌈

OMAPI β€” Object Management Application Programming Interface. that's the whole name, no cap. πŸ‘‘


✨ DESCRIPTION ✨

OMAPI is a programming layer built for controlling remote applications and for querying them for their state. rn it's used by the ISC DHCP server, and this outline is all about the parts of OMAPI that matter to clients of that DHCP server. it does this by also describing the use of a thin API layered on top of OMAPI called dhcpctl πŸ¦‹

OMAPI uses TCP/IP as the transport for server communication, and you can impose security by having the client and server cryptographically sign messages using a shared secret. cute AND safe πŸ’œ

so how does dhcpctl actually work? it presents the client with handles to objects that act as surrogates for the real objects living in the server. like, a client will create a handle for a lease object, and then ask the server to fill that lease handle's state. after that the client application can pull details like the lease expiration time straight out of the lease handle. iconic. πŸŽ€

and you can modify server state too: create handles to new objects, or modify the attributes of handles to existing objects, and then tell the server to update itself according to the changes you made. slay πŸ’…


πŸ› οΈ USAGE πŸ› οΈ

first rule, no exceptions: your client application must always call dhcpctl_initialize() before making calls to any other dhcpctl functions. this sets up various internal data structures for you. do not skip it, bestie 😭

to create the connection to the server, your client has to use dhcpctl_connect(). as well as making the physical connection, it also sets up the connection data structures to do authentication on each message, if that's required. 🫢

every single dhcpctl function returns an integer value of type isc_result_t. a successful call gives you back ISC_R_SUCCESS. if the call fails for a reason that's local to the client (think: insufficient local memory, or invalid arguments to the call) then the return value of the dhcpctl function will show that. but β€” plot twist β€” if the call succeeds and the server still couldn't process the request, then the error value from the server comes back through another way, shown below. πŸ‘€

the easiest way to understand dhcpctl is literally just to see it in action. the following program is fully functional, but almost all of the error checking has been removed to make it shorter and easier to understand. what it does: query the server running on the localhost for the details of the lease for IP address 10.0.0.101, then print out the time the lease ends. periodt. πŸ’–

#include <stdarg.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>

#include <isc/result.h>
#include <dhcpctl/dhcpctl.h>

int main (int argc, char **argv) {
     dhcpctl_data_string ipaddrstring = NULL;
     dhcpctl_data_string value = NULL;

okay so heads up: all modifications of handles and all accesses of handle data happen via dhcpctl_data_string objects. that's the vibe. ✨

     dhcpctl_handle connection = NULL;
     dhcpctl_handle lease = NULL;
     isc_result_t waitstatus;
     struct in_addr convaddr;
     time_t thetime;

     dhcpctl_initialize ();

that right there is the required first step. don't move on without it. πŸ™ˆ

     dhcpctl_connect (&connection, "127.0.0.1", 7911, 0);

this sets up the connection to the server. the server normally listens on port 7911 unless it's been configured to do otherwise. πŸ“‘

     dhcpctl_new_object (&lease, connection, "lease");

here we create a handle to a lease. important: this call just sets up local data structure. the server hasn't yet made any association between the client's data structure and any lease it has. it's a vibe, not a binding. πŸ’«

     memset (&ipaddrstring, 0, sizeof ipaddrstring);

     inet_pton(AF_INET, "10.0.0.101", &convaddr);

     omapi_data_string_new (&ipaddrstring, 4, MDL);

create a new data string to store in the handle. πŸŽ€

     memcpy(ipaddrstring->value, &convaddr.s_addr, 4);

     dhcpctl_set_value (lease, ipaddrstring, "ip-address");

so here we're setting the ip-address attribute of the lease handle to the given address. we haven't set any other attributes, so when the server makes the association, the ip address will be all it uses to look up the lease in its tables. that's the whole search key, bestie. πŸ”

     dhcpctl_open_object (lease, connection, 0);

here we prime the connection with the request to look up the lease in the server and fill up the local handle with the attributes the server will send over in its answer. πŸ“¨

     dhcpctl_wait_for_completion (lease, &waitstatus);

this call is what actually causes the message to get sent to the server (the message to look up the lease and send back the attribute values in the answer). the value in the variable waitstatus when the function returns will be the result from the server. if the message couldn't be processed properly by the server, then the error will be reflected here. πŸ‘‘

     if (waitstatus != ISC_R_SUCCESS) {
          /* server not authoritative */
          exit (0);
     }

     dhcpctl_data_string_dereference(&ipaddrstring, MDL);

clean-up of memory we no longer need. be a good citizen 🧚

     dhcpctl_get_value (&value, lease, "ends");

get the attribute named ends from the lease handle. this is a 4-byte integer of the time (in unix epoch seconds) that the lease will expire. ⏰

     memcpy(&thetime, value->value, value->len);
     dhcpctl_data_string_dereference(&value, MDL);

     fprintf (stdout, "ending time is %s", ctime(&thetime));
}

and that's the whole program. ate. πŸ’…


πŸ” AUTHENTICATION πŸ”

if the server demands authenticated connections, then before opening the connection the user must call dhcpctl_new_authenticator. no skipping this step, it's the bouncer at the club πŸšͺ

dhcpctl_handle authenticator = NULL;
const char *keyname = "a-key-name";
const char *algorithm = "hmac-md5";
const char *secret = "a-shared-secret";

dhcpctl_new_authenticator (&authenticator,
                                 keyname,
                                 algorithm,
                                 secret,
                  strlen(secret) + 1);

the keyname and algorithm must all match what's specified in the server's dhcpd.conf file, excepting that the secret should appear in raw form, not in base64 as it would in dhcpd.conf. read that again, it matters πŸ‘€

key "a-key-name" {
     algorithm hmac-md5;
     secret "a-shared-secret";
};

# Set the omapi-key value to use
# authenticated connections
omapi-key a-key-name;

the authenticator handle that gets created by the call to dhcpctl_new_authenticator must be given as the last (the 4th) argument to the call to dhcpctl_connect(). after that, all messages will be signed with the given secret string using the specified algorithm. secure AND cute πŸŽ€


πŸ‘€ SEE ALSO πŸ‘€

dhcpctl(3), omshell(1), dhcpd(8), dhclient(8), dhcpd.conf(5), dhclient.conf(5).

go read those next, bestie, they're the rest of the lore πŸ“š


πŸ’œ AUTHOR πŸ’œ

omapi is maintained by ISC. to learn more about Internet Systems Consortium, see https://www.isc.org 🌐


and that's a wrap on the omapi(3) page πŸ’– straight out of the Library Functions Manual, brought to you by your local Unix bestie. now go call dhcpctl_initialize() first, like we talked about. mwah πŸ«Άβœ¨πŸŽ€

πŸ“¦ where this page comes from