util.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <dhcpmsg.h>
#include <ctype.h>
#include <netdb.h>
#include <fcntl.h>
#include <stdio.h>
#include "states.h"
#include "agent.h"
#include "interface.h"
#include "util.h"
#include "packet.h"
#include "defaults.h"
/*
* this file contains utility functions that have no real better home
* of their own. they can largely be broken into six categories:
*
* o conversion functions -- functions to turn integers into strings,
* or to convert between units of a similar measure.
*
* o ipc-related functions -- functions to simplify the generation of
* ipc messages to the agent's clients.
*
* o signal-related functions -- functions to clean up the agent when
* it receives a signal.
*
* o routing table manipulation functions
*
* o acknak handler functions
*
* o true miscellany -- anything else
*/
/*
* pkt_type_to_string(): stringifies a packet type
*
* input: uchar_t: a DHCP packet type value, as defined in RFC2131
* output: const char *: the stringified packet type
*/
const char *
{
/*
* note: the ordering here allows direct indexing of the table
* based on the RFC2131 packet type value passed in.
*/
static const char *types[] = {
"BOOTP", "DISCOVER", "OFFER", "REQUEST", "DECLINE",
"ACK", "NAK", "RELEASE", "INFORM"
};
return ("<unknown>");
}
/*
* dlpi_to_arp(): converts DLPI datalink types into ARP datalink types
*
* input: uchar_t: the DLPI datalink type
* output: uchar_t: the ARP datalink type (0 if no corresponding code)
*/
{
switch (dlpi_type) {
case DL_ETHER:
return (1);
case DL_FRAME:
return (15);
case DL_ATM:
return (16);
case DL_HDLC:
return (17);
case DL_FC:
return (18);
case DL_CSMACD: /* ieee 802 networks */
case DL_TPB:
case DL_TPR:
case DL_METRO:
case DL_FDDI:
return (6);
case DL_IB:
return (ARPHRD_IB);
}
return (0);
}
/*
* monosec_to_string(): converts a monosec_t into a date string
*
* input: monosec_t: the monosec_t to convert
* output: const char *: the corresponding date string
*/
const char *
{
/* strip off the newline -- ugh, why, why, why.. */
return (time_string);
}
/*
* monosec(): returns a monotonically increasing time in seconds that
* is not affected by stime(2) or adjtime(2).
*
* input: void
* output: monosec_t: the number of seconds since some time in the past
*/
monosec(void)
{
}
/*
* monosec_to_time(): converts a monosec_t into real wall time
*
* input: monosec_t: the absolute monosec_t to convert
* output: time_t: the absolute time that monosec_t represents in wall time
*/
{
}
/*
* send_ok_reply(): sends an "ok" reply to a request and closes the ipc
* connection
*
* input: dhcp_ipc_request_t *: the request to reply to
* int *: the ipc connection file descriptor (set to -1 on return)
* output: void
* note: the request is freed (thus the request must be on the heap).
*/
void
{
}
/*
* send_error_reply(): sends an "error" reply to a request and closes the ipc
* connection
*
* input: dhcp_ipc_request_t *: the request to reply to
* int: the error to send back on the ipc connection
* int *: the ipc connection file descriptor (set to -1 on return)
* output: void
* note: the request is freed (thus the request must be on the heap).
*/
void
{
}
/*
* send_data_reply(): sends a reply to a request and closes the ipc connection
*
* input: dhcp_ipc_request_t *: the request to reply to
* int *: the ipc connection file descriptor (set to -1 on return)
* int: the status to send back on the ipc connection (zero for
* success, DHCP_IPC_E_* otherwise).
* dhcp_data_type_t: the type of the payload in the reply
* void *: the payload for the reply, or NULL if there is no payload
* size_t: the size of the payload
* output: void
* note: the request is freed (thus the request must be on the heap).
*/
void
{
if (*control_fd == -1)
return;
/*
* free the request since we've now used it to send our reply.
* we can also close the socket since the reply has been sent.
*/
(void) dhcp_ipc_close(*control_fd);
*control_fd = -1;
}
/*
* print_server_msg(): prints a message from a DHCP server
*
* input: struct ifslist *: the interface the message came in on
* DHCP_OPT *: the option containing the string to display
* output: void
*/
void
{
}
/*
* alrm_exit(): Signal handler for SIGARLM. terminates grandparent.
*
* input: int: signal the handler was called with.
*
* output: void
*/
static void
{
int exitval;
else
}
/*
* daemonize(): daemonizes the process
*
* input: void
* output: int: 1 on success, 0 on failure
*/
int
daemonize(void)
{
/*
* We've found that adoption takes sufficiently long that
* a dhcpinfo run after dhcpagent -a is started may occur
* before the agent is ready to process the request.
* The result is an error message and an unhappy user.
*
* The initial process now sleeps for DHCP_ADOPT_SLEEP,
* unless interrupted by a SIGALRM, in which case it
* exits immediately. This has the effect that the
* grandparent doesn't exit until the dhcpagent is ready
* to process requests. This defers the the balance of
* the system start-up script processing until the
* dhcpagent is ready to field requests.
*
* grandparent is only set for the adopt case; other
* cases do not require the wait.
*/
if (grandparent != 0)
switch (fork()) {
case -1:
return (0);
case 0:
if (grandparent != 0)
/*
* setsid() makes us lose our controlling terminal,
* and become both a session leader and a process
* group leader.
*/
(void) setsid();
/*
* under POSIX, a session leader can accidentally
* (through open(2)) acquire a controlling terminal if
* it does not have one. just to be safe, fork again
* so we are not a session leader.
*/
switch (fork()) {
case -1:
return (0);
case 0:
(void) chdir("/");
(void) umask(022);
closefrom(0);
break;
default:
}
break;
default:
if (grandparent != 0) {
"waiting for adoption to complete.");
if (sleep(DHCP_ADOPT_SLEEP) == 0) {
"timed out awaiting adoption.");
}
}
}
return (1);
}
/*
* update_default_route(): update the interface's default route
*
* input: int: the type of message; either RTM_ADD or RTM_DELETE
* struct in_addr: the default gateway to use
* const char *: the interface associated with the route
* int: any additional flags (besides RTF_STATIC and RTF_GATEWAY)
* output: int: 1 on success, 0 on failure
*/
static int
int flags)
{
static int rtsock_fd = -1;
struct {
struct sockaddr_in rm_dst;
struct sockaddr_in rm_gw;
struct sockaddr_in rm_mask;
struct sockaddr_dl rm_ifp;
} rtmsg;
if (rtsock_fd == -1) {
if (rtsock_fd == -1) {
"cannot create routing socket");
return (0);
}
}
}
/*
* add_default_route(): add the default route to the given gateway
*
* input: const char *: the name of the interface associated with the route
* struct in_addr: the default gateway to add
* output: int: 1 on success, 0 on failure
*/
int
{
return (1);
}
/*
* del_default_route(): deletes the default route to the given gateway
*
* input: const char *: the name of the interface associated with the route
* struct in_addr: if not INADDR_ANY, the default gateway to remove
* output: int: 1 on success, 0 on failure
*/
int
{
return (1);
return (1);
}
/*
* inactivity_shutdown(): shuts down agent if there are no interfaces to manage
*
* input: iu_tq_t *: unused
* void *: unused
* output: void
*/
/* ARGSUSED */
void
{
if (ifs_count() > 0) /* shouldn't happen, but... */
return;
}
/*
* graceful_shutdown(): shuts down the agent gracefully
*
* input: int: the signal that caused graceful_shutdown to be called
* output: void
*/
void
graceful_shutdown(int sig)
{
}
/*
* register_acknak(): registers dhcp_acknak() to be called back when ACK or
* NAK packets are received on a given interface
*
* input: struct ifslist *: the interface to register for
* output: int: 1 on success, 0 on failure
*/
int
{
/*
* having an acknak id already registered isn't impossible;
* handle the situation as gracefully as possible.
*/
"attempting to cancel");
if (unregister_acknak(ifsp) == 0)
return (0);
}
case BOUND:
case REBINDING:
case RENEWING:
dhcp_acknak, ifsp);
if (ack_bcast_id == -1) {
"register to receive socket broadcasts");
return (0);
}
dhcp_acknak, ifsp);
break;
default:
dhcp_acknak, ifsp);
break;
}
if (ack_id == -1) {
return (0);
}
"%d", ack_bcast_id);
}
return (1);
}
/*
* unregister_acknak(): unregisters dhcp_acknak() to be called back
*
* input: struct ifslist *: the interface to unregister for
* output: int: 1 on success, 0 on failure
*/
int
{
"unregister acknak id %d on %s",
return (0);
}
(void) release_ifs(ifsp);
}
== 0) {
"unregister broadcast id %d on %s",
return (0);
}
(void) release_ifs(ifsp);
}
return (1);
}
/*
* bind_sock(): binds a socket to a given IP address and port number
*
* input: int: the socket to bind
* in_port_t: the port number to bind to, host byte order
* in_addr_t: the address to bind to, host byte order
* output: int: 1 on success, 0 on failure
*/
int
{
struct sockaddr_in sin;
int on = 1;
}
/*
* valid_hostname(): check whether a string is a valid hostname
*
* input: const char *: the string to verify as a hostname
* output: boolean_t: B_TRUE if the string is a valid hostname
*
* Note that we accept both host names beginning with a digit and
* those containing hyphens. Neither is strictly legal according
* to the RFCs, but both are in common practice, so we endeavour
* to not break what customers are using.
*/
static boolean_t
valid_hostname(const char *hostname)
{
unsigned int i;
for (i = 0; hostname[i] != '\0'; i++) {
continue;
return (B_FALSE);
}
return (i > 0);
}
/*
* iffile_to_hostname(): return the hostname contained on a line of the form
*
* [ ^I]*inet[ ^I]+hostname[\n]*\0
*
* in the file located at the specified path
*
* input: const char *: the path of the file to look in for the hostname
* output: const char *: the hostname at that path, or NULL on failure
*/
const char *
iffile_to_hostname(const char *path)
{
static char ifline[IFLINE_MAX];
return (NULL);
/*
* such command is on a separate line (see the "while read ifcmds" code
* time, searching for a line of the form
*
* [ ^I]*inet[ ^I]+hostname[\n]*\0
*
* extract the host name from it, and check it for validity.
*/
char *p;
return (NULL);
}
p += 4; /* skip over "inet" and expect spaces or tabs */
if ((*p == '\n') || (*p == '\0')) {
return (NULL);
}
if (isspace(*p)) {
char *nlptr;
/* no need to read more of the file */
while (isspace(*p))
p++;
*nlptr = '\0';
if (strlen(p) > MAXHOSTNAMELEN) {
"iffile_to_hostname:"
" host name too long");
return (NULL);
}
if (valid_hostname(p)) {
return (p);
} else {
"iffile_to_hostname:"
" host name not valid");
return (NULL);
}
} else {
return (NULL);
}
}
}
return (NULL);
}