1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <unistd.h> 30*0Sstevel@tonic-gate #include <sys/types.h> 31*0Sstevel@tonic-gate #include <sys/stat.h> 32*0Sstevel@tonic-gate #include <stdlib.h> 33*0Sstevel@tonic-gate #include <netinet/in.h> /* struct in_addr */ 34*0Sstevel@tonic-gate #include <netinet/dhcp.h> 35*0Sstevel@tonic-gate #include <signal.h> 36*0Sstevel@tonic-gate #include <sys/dlpi.h> 37*0Sstevel@tonic-gate #include <sys/sockio.h> 38*0Sstevel@tonic-gate #include <sys/socket.h> 39*0Sstevel@tonic-gate #include <errno.h> 40*0Sstevel@tonic-gate #include <net/route.h> 41*0Sstevel@tonic-gate #include <net/if_arp.h> 42*0Sstevel@tonic-gate #include <string.h> 43*0Sstevel@tonic-gate #include <dhcpmsg.h> 44*0Sstevel@tonic-gate #include <ctype.h> 45*0Sstevel@tonic-gate #include <netdb.h> 46*0Sstevel@tonic-gate #include <fcntl.h> 47*0Sstevel@tonic-gate #include <stdio.h> 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate #include "states.h" 50*0Sstevel@tonic-gate #include "agent.h" 51*0Sstevel@tonic-gate #include "interface.h" 52*0Sstevel@tonic-gate #include "util.h" 53*0Sstevel@tonic-gate #include "packet.h" 54*0Sstevel@tonic-gate #include "defaults.h" 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate /* 57*0Sstevel@tonic-gate * this file contains utility functions that have no real better home 58*0Sstevel@tonic-gate * of their own. they can largely be broken into six categories: 59*0Sstevel@tonic-gate * 60*0Sstevel@tonic-gate * o conversion functions -- functions to turn integers into strings, 61*0Sstevel@tonic-gate * or to convert between units of a similar measure. 62*0Sstevel@tonic-gate * 63*0Sstevel@tonic-gate * o ipc-related functions -- functions to simplify the generation of 64*0Sstevel@tonic-gate * ipc messages to the agent's clients. 65*0Sstevel@tonic-gate * 66*0Sstevel@tonic-gate * o signal-related functions -- functions to clean up the agent when 67*0Sstevel@tonic-gate * it receives a signal. 68*0Sstevel@tonic-gate * 69*0Sstevel@tonic-gate * o routing table manipulation functions 70*0Sstevel@tonic-gate * 71*0Sstevel@tonic-gate * o acknak handler functions 72*0Sstevel@tonic-gate * 73*0Sstevel@tonic-gate * o true miscellany -- anything else 74*0Sstevel@tonic-gate */ 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate /* 77*0Sstevel@tonic-gate * pkt_type_to_string(): stringifies a packet type 78*0Sstevel@tonic-gate * 79*0Sstevel@tonic-gate * input: uchar_t: a DHCP packet type value, as defined in RFC2131 80*0Sstevel@tonic-gate * output: const char *: the stringified packet type 81*0Sstevel@tonic-gate */ 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate const char * 84*0Sstevel@tonic-gate pkt_type_to_string(uchar_t type) 85*0Sstevel@tonic-gate { 86*0Sstevel@tonic-gate /* 87*0Sstevel@tonic-gate * note: the ordering here allows direct indexing of the table 88*0Sstevel@tonic-gate * based on the RFC2131 packet type value passed in. 89*0Sstevel@tonic-gate */ 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate static const char *types[] = { 92*0Sstevel@tonic-gate "BOOTP", "DISCOVER", "OFFER", "REQUEST", "DECLINE", 93*0Sstevel@tonic-gate "ACK", "NAK", "RELEASE", "INFORM" 94*0Sstevel@tonic-gate }; 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate if (type >= (sizeof (types) / sizeof (*types)) || types[type] == NULL) 97*0Sstevel@tonic-gate return ("<unknown>"); 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate return (types[type]); 100*0Sstevel@tonic-gate } 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate /* 103*0Sstevel@tonic-gate * dlpi_to_arp(): converts DLPI datalink types into ARP datalink types 104*0Sstevel@tonic-gate * 105*0Sstevel@tonic-gate * input: uchar_t: the DLPI datalink type 106*0Sstevel@tonic-gate * output: uchar_t: the ARP datalink type (0 if no corresponding code) 107*0Sstevel@tonic-gate */ 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gate uchar_t 110*0Sstevel@tonic-gate dlpi_to_arp(uchar_t dlpi_type) 111*0Sstevel@tonic-gate { 112*0Sstevel@tonic-gate switch (dlpi_type) { 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate case DL_ETHER: 115*0Sstevel@tonic-gate return (1); 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate case DL_FRAME: 118*0Sstevel@tonic-gate return (15); 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate case DL_ATM: 121*0Sstevel@tonic-gate return (16); 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gate case DL_HDLC: 124*0Sstevel@tonic-gate return (17); 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate case DL_FC: 127*0Sstevel@tonic-gate return (18); 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate case DL_CSMACD: /* ieee 802 networks */ 130*0Sstevel@tonic-gate case DL_TPB: 131*0Sstevel@tonic-gate case DL_TPR: 132*0Sstevel@tonic-gate case DL_METRO: 133*0Sstevel@tonic-gate case DL_FDDI: 134*0Sstevel@tonic-gate return (6); 135*0Sstevel@tonic-gate case DL_IB: 136*0Sstevel@tonic-gate return (ARPHRD_IB); 137*0Sstevel@tonic-gate } 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate return (0); 140*0Sstevel@tonic-gate } 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate /* 143*0Sstevel@tonic-gate * monosec_to_string(): converts a monosec_t into a date string 144*0Sstevel@tonic-gate * 145*0Sstevel@tonic-gate * input: monosec_t: the monosec_t to convert 146*0Sstevel@tonic-gate * output: const char *: the corresponding date string 147*0Sstevel@tonic-gate */ 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate const char * 150*0Sstevel@tonic-gate monosec_to_string(monosec_t monosec) 151*0Sstevel@tonic-gate { 152*0Sstevel@tonic-gate time_t time = monosec_to_time(monosec); 153*0Sstevel@tonic-gate char *time_string = ctime(&time); 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate /* strip off the newline -- ugh, why, why, why.. */ 156*0Sstevel@tonic-gate time_string[strlen(time_string) - 1] = '\0'; 157*0Sstevel@tonic-gate return (time_string); 158*0Sstevel@tonic-gate } 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gate /* 161*0Sstevel@tonic-gate * monosec(): returns a monotonically increasing time in seconds that 162*0Sstevel@tonic-gate * is not affected by stime(2) or adjtime(2). 163*0Sstevel@tonic-gate * 164*0Sstevel@tonic-gate * input: void 165*0Sstevel@tonic-gate * output: monosec_t: the number of seconds since some time in the past 166*0Sstevel@tonic-gate */ 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate monosec_t 169*0Sstevel@tonic-gate monosec(void) 170*0Sstevel@tonic-gate { 171*0Sstevel@tonic-gate return (gethrtime() / NANOSEC); 172*0Sstevel@tonic-gate } 173*0Sstevel@tonic-gate 174*0Sstevel@tonic-gate /* 175*0Sstevel@tonic-gate * monosec_to_time(): converts a monosec_t into real wall time 176*0Sstevel@tonic-gate * 177*0Sstevel@tonic-gate * input: monosec_t: the absolute monosec_t to convert 178*0Sstevel@tonic-gate * output: time_t: the absolute time that monosec_t represents in wall time 179*0Sstevel@tonic-gate */ 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gate time_t 182*0Sstevel@tonic-gate monosec_to_time(monosec_t abs_monosec) 183*0Sstevel@tonic-gate { 184*0Sstevel@tonic-gate return (abs_monosec - monosec()) + time(NULL); 185*0Sstevel@tonic-gate } 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate /* 188*0Sstevel@tonic-gate * send_ok_reply(): sends an "ok" reply to a request and closes the ipc 189*0Sstevel@tonic-gate * connection 190*0Sstevel@tonic-gate * 191*0Sstevel@tonic-gate * input: dhcp_ipc_request_t *: the request to reply to 192*0Sstevel@tonic-gate * int *: the ipc connection file descriptor (set to -1 on return) 193*0Sstevel@tonic-gate * output: void 194*0Sstevel@tonic-gate * note: the request is freed (thus the request must be on the heap). 195*0Sstevel@tonic-gate */ 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate void 198*0Sstevel@tonic-gate send_ok_reply(dhcp_ipc_request_t *request, int *control_fd) 199*0Sstevel@tonic-gate { 200*0Sstevel@tonic-gate send_error_reply(request, 0, control_fd); 201*0Sstevel@tonic-gate } 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate /* 204*0Sstevel@tonic-gate * send_error_reply(): sends an "error" reply to a request and closes the ipc 205*0Sstevel@tonic-gate * connection 206*0Sstevel@tonic-gate * 207*0Sstevel@tonic-gate * input: dhcp_ipc_request_t *: the request to reply to 208*0Sstevel@tonic-gate * int: the error to send back on the ipc connection 209*0Sstevel@tonic-gate * int *: the ipc connection file descriptor (set to -1 on return) 210*0Sstevel@tonic-gate * output: void 211*0Sstevel@tonic-gate * note: the request is freed (thus the request must be on the heap). 212*0Sstevel@tonic-gate */ 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate void 215*0Sstevel@tonic-gate send_error_reply(dhcp_ipc_request_t *request, int error, int *control_fd) 216*0Sstevel@tonic-gate { 217*0Sstevel@tonic-gate send_data_reply(request, control_fd, error, DHCP_TYPE_NONE, NULL, NULL); 218*0Sstevel@tonic-gate } 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate /* 221*0Sstevel@tonic-gate * send_data_reply(): sends a reply to a request and closes the ipc connection 222*0Sstevel@tonic-gate * 223*0Sstevel@tonic-gate * input: dhcp_ipc_request_t *: the request to reply to 224*0Sstevel@tonic-gate * int *: the ipc connection file descriptor (set to -1 on return) 225*0Sstevel@tonic-gate * int: the status to send back on the ipc connection (zero for 226*0Sstevel@tonic-gate * success, DHCP_IPC_E_* otherwise). 227*0Sstevel@tonic-gate * dhcp_data_type_t: the type of the payload in the reply 228*0Sstevel@tonic-gate * void *: the payload for the reply, or NULL if there is no payload 229*0Sstevel@tonic-gate * size_t: the size of the payload 230*0Sstevel@tonic-gate * output: void 231*0Sstevel@tonic-gate * note: the request is freed (thus the request must be on the heap). 232*0Sstevel@tonic-gate */ 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate void 235*0Sstevel@tonic-gate send_data_reply(dhcp_ipc_request_t *request, int *control_fd, 236*0Sstevel@tonic-gate int error, dhcp_data_type_t type, void *buffer, size_t size) 237*0Sstevel@tonic-gate { 238*0Sstevel@tonic-gate dhcp_ipc_reply_t *reply; 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate if (*control_fd == -1) 241*0Sstevel@tonic-gate return; 242*0Sstevel@tonic-gate 243*0Sstevel@tonic-gate reply = dhcp_ipc_alloc_reply(request, error, buffer, size, type); 244*0Sstevel@tonic-gate if (reply == NULL) 245*0Sstevel@tonic-gate dhcpmsg(MSG_ERR, "send_data_reply: cannot allocate reply"); 246*0Sstevel@tonic-gate 247*0Sstevel@tonic-gate else if (dhcp_ipc_send_reply(*control_fd, reply) != 0) 248*0Sstevel@tonic-gate dhcpmsg(MSG_ERR, "send_data_reply: dhcp_ipc_send_reply"); 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate /* 251*0Sstevel@tonic-gate * free the request since we've now used it to send our reply. 252*0Sstevel@tonic-gate * we can also close the socket since the reply has been sent. 253*0Sstevel@tonic-gate */ 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate free(reply); 256*0Sstevel@tonic-gate free(request); 257*0Sstevel@tonic-gate (void) dhcp_ipc_close(*control_fd); 258*0Sstevel@tonic-gate *control_fd = -1; 259*0Sstevel@tonic-gate } 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate /* 262*0Sstevel@tonic-gate * print_server_msg(): prints a message from a DHCP server 263*0Sstevel@tonic-gate * 264*0Sstevel@tonic-gate * input: struct ifslist *: the interface the message came in on 265*0Sstevel@tonic-gate * DHCP_OPT *: the option containing the string to display 266*0Sstevel@tonic-gate * output: void 267*0Sstevel@tonic-gate */ 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate void 270*0Sstevel@tonic-gate print_server_msg(struct ifslist *ifsp, DHCP_OPT *p) 271*0Sstevel@tonic-gate { 272*0Sstevel@tonic-gate dhcpmsg(MSG_INFO, "%s: message from server: %.*s", ifsp->if_name, 273*0Sstevel@tonic-gate p->len, p->value); 274*0Sstevel@tonic-gate } 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate /* 277*0Sstevel@tonic-gate * alrm_exit(): Signal handler for SIGARLM. terminates grandparent. 278*0Sstevel@tonic-gate * 279*0Sstevel@tonic-gate * input: int: signal the handler was called with. 280*0Sstevel@tonic-gate * 281*0Sstevel@tonic-gate * output: void 282*0Sstevel@tonic-gate */ 283*0Sstevel@tonic-gate 284*0Sstevel@tonic-gate static void 285*0Sstevel@tonic-gate alrm_exit(int sig) 286*0Sstevel@tonic-gate { 287*0Sstevel@tonic-gate int exitval; 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate if (sig == SIGALRM && grandparent != 0) 290*0Sstevel@tonic-gate exitval = EXIT_SUCCESS; 291*0Sstevel@tonic-gate else 292*0Sstevel@tonic-gate exitval = EXIT_FAILURE; 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate _exit(exitval); 295*0Sstevel@tonic-gate } 296*0Sstevel@tonic-gate 297*0Sstevel@tonic-gate /* 298*0Sstevel@tonic-gate * daemonize(): daemonizes the process 299*0Sstevel@tonic-gate * 300*0Sstevel@tonic-gate * input: void 301*0Sstevel@tonic-gate * output: int: 1 on success, 0 on failure 302*0Sstevel@tonic-gate */ 303*0Sstevel@tonic-gate 304*0Sstevel@tonic-gate int 305*0Sstevel@tonic-gate daemonize(void) 306*0Sstevel@tonic-gate { 307*0Sstevel@tonic-gate /* 308*0Sstevel@tonic-gate * We've found that adoption takes sufficiently long that 309*0Sstevel@tonic-gate * a dhcpinfo run after dhcpagent -a is started may occur 310*0Sstevel@tonic-gate * before the agent is ready to process the request. 311*0Sstevel@tonic-gate * The result is an error message and an unhappy user. 312*0Sstevel@tonic-gate * 313*0Sstevel@tonic-gate * The initial process now sleeps for DHCP_ADOPT_SLEEP, 314*0Sstevel@tonic-gate * unless interrupted by a SIGALRM, in which case it 315*0Sstevel@tonic-gate * exits immediately. This has the effect that the 316*0Sstevel@tonic-gate * grandparent doesn't exit until the dhcpagent is ready 317*0Sstevel@tonic-gate * to process requests. This defers the the balance of 318*0Sstevel@tonic-gate * the system start-up script processing until the 319*0Sstevel@tonic-gate * dhcpagent is ready to field requests. 320*0Sstevel@tonic-gate * 321*0Sstevel@tonic-gate * grandparent is only set for the adopt case; other 322*0Sstevel@tonic-gate * cases do not require the wait. 323*0Sstevel@tonic-gate */ 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate if (grandparent != 0) 326*0Sstevel@tonic-gate (void) signal(SIGALRM, alrm_exit); 327*0Sstevel@tonic-gate 328*0Sstevel@tonic-gate switch (fork()) { 329*0Sstevel@tonic-gate 330*0Sstevel@tonic-gate case -1: 331*0Sstevel@tonic-gate return (0); 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate case 0: 334*0Sstevel@tonic-gate if (grandparent != 0) 335*0Sstevel@tonic-gate (void) signal(SIGALRM, SIG_DFL); 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate /* 338*0Sstevel@tonic-gate * setsid() makes us lose our controlling terminal, 339*0Sstevel@tonic-gate * and become both a session leader and a process 340*0Sstevel@tonic-gate * group leader. 341*0Sstevel@tonic-gate */ 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate (void) setsid(); 344*0Sstevel@tonic-gate 345*0Sstevel@tonic-gate /* 346*0Sstevel@tonic-gate * under POSIX, a session leader can accidentally 347*0Sstevel@tonic-gate * (through open(2)) acquire a controlling terminal if 348*0Sstevel@tonic-gate * it does not have one. just to be safe, fork again 349*0Sstevel@tonic-gate * so we are not a session leader. 350*0Sstevel@tonic-gate */ 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gate switch (fork()) { 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate case -1: 355*0Sstevel@tonic-gate return (0); 356*0Sstevel@tonic-gate 357*0Sstevel@tonic-gate case 0: 358*0Sstevel@tonic-gate (void) signal(SIGHUP, SIG_IGN); 359*0Sstevel@tonic-gate (void) chdir("/"); 360*0Sstevel@tonic-gate (void) umask(022); 361*0Sstevel@tonic-gate closefrom(0); 362*0Sstevel@tonic-gate break; 363*0Sstevel@tonic-gate 364*0Sstevel@tonic-gate default: 365*0Sstevel@tonic-gate _exit(EXIT_SUCCESS); 366*0Sstevel@tonic-gate } 367*0Sstevel@tonic-gate break; 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate default: 370*0Sstevel@tonic-gate if (grandparent != 0) { 371*0Sstevel@tonic-gate (void) signal(SIGCHLD, SIG_IGN); 372*0Sstevel@tonic-gate dhcpmsg(MSG_DEBUG, "dhcpagent: daemonize: " 373*0Sstevel@tonic-gate "waiting for adoption to complete."); 374*0Sstevel@tonic-gate if (sleep(DHCP_ADOPT_SLEEP) == 0) { 375*0Sstevel@tonic-gate dhcpmsg(MSG_WARNING, "dhcpagent: daemonize: " 376*0Sstevel@tonic-gate "timed out awaiting adoption."); 377*0Sstevel@tonic-gate } 378*0Sstevel@tonic-gate } 379*0Sstevel@tonic-gate _exit(EXIT_SUCCESS); 380*0Sstevel@tonic-gate } 381*0Sstevel@tonic-gate 382*0Sstevel@tonic-gate return (1); 383*0Sstevel@tonic-gate } 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate /* 386*0Sstevel@tonic-gate * update_default_route(): update the interface's default route 387*0Sstevel@tonic-gate * 388*0Sstevel@tonic-gate * input: int: the type of message; either RTM_ADD or RTM_DELETE 389*0Sstevel@tonic-gate * struct in_addr: the default gateway to use 390*0Sstevel@tonic-gate * const char *: the interface associated with the route 391*0Sstevel@tonic-gate * int: any additional flags (besides RTF_STATIC and RTF_GATEWAY) 392*0Sstevel@tonic-gate * output: int: 1 on success, 0 on failure 393*0Sstevel@tonic-gate */ 394*0Sstevel@tonic-gate 395*0Sstevel@tonic-gate static int 396*0Sstevel@tonic-gate update_default_route(const char *ifname, int type, struct in_addr *gateway_nbo, 397*0Sstevel@tonic-gate int flags) 398*0Sstevel@tonic-gate { 399*0Sstevel@tonic-gate static int rtsock_fd = -1; 400*0Sstevel@tonic-gate struct { 401*0Sstevel@tonic-gate struct rt_msghdr rm_mh; 402*0Sstevel@tonic-gate struct sockaddr_in rm_dst; 403*0Sstevel@tonic-gate struct sockaddr_in rm_gw; 404*0Sstevel@tonic-gate struct sockaddr_in rm_mask; 405*0Sstevel@tonic-gate struct sockaddr_dl rm_ifp; 406*0Sstevel@tonic-gate } rtmsg; 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate if (rtsock_fd == -1) { 409*0Sstevel@tonic-gate rtsock_fd = socket(PF_ROUTE, SOCK_RAW, 0); 410*0Sstevel@tonic-gate if (rtsock_fd == -1) { 411*0Sstevel@tonic-gate dhcpmsg(MSG_ERR, "update_default_route: " 412*0Sstevel@tonic-gate "cannot create routing socket"); 413*0Sstevel@tonic-gate return (0); 414*0Sstevel@tonic-gate } 415*0Sstevel@tonic-gate } 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate (void) memset(&rtmsg, 0, sizeof (rtmsg)); 418*0Sstevel@tonic-gate rtmsg.rm_mh.rtm_version = RTM_VERSION; 419*0Sstevel@tonic-gate rtmsg.rm_mh.rtm_msglen = sizeof (rtmsg); 420*0Sstevel@tonic-gate rtmsg.rm_mh.rtm_type = type; 421*0Sstevel@tonic-gate rtmsg.rm_mh.rtm_pid = getpid(); 422*0Sstevel@tonic-gate rtmsg.rm_mh.rtm_flags = RTF_GATEWAY | RTF_STATIC | flags; 423*0Sstevel@tonic-gate rtmsg.rm_mh.rtm_addrs = RTA_GATEWAY | RTA_DST | RTA_NETMASK | RTA_IFP; 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate rtmsg.rm_gw.sin_family = AF_INET; 426*0Sstevel@tonic-gate rtmsg.rm_gw.sin_addr = *gateway_nbo; 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate rtmsg.rm_dst.sin_family = AF_INET; 429*0Sstevel@tonic-gate rtmsg.rm_dst.sin_addr.s_addr = htonl(INADDR_ANY); 430*0Sstevel@tonic-gate 431*0Sstevel@tonic-gate rtmsg.rm_mask.sin_family = AF_INET; 432*0Sstevel@tonic-gate rtmsg.rm_mask.sin_addr.s_addr = htonl(0); 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate rtmsg.rm_ifp.sdl_family = AF_LINK; 435*0Sstevel@tonic-gate rtmsg.rm_ifp.sdl_index = if_nametoindex(ifname); 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate return (write(rtsock_fd, &rtmsg, sizeof (rtmsg)) == sizeof (rtmsg)); 438*0Sstevel@tonic-gate } 439*0Sstevel@tonic-gate 440*0Sstevel@tonic-gate /* 441*0Sstevel@tonic-gate * add_default_route(): add the default route to the given gateway 442*0Sstevel@tonic-gate * 443*0Sstevel@tonic-gate * input: const char *: the name of the interface associated with the route 444*0Sstevel@tonic-gate * struct in_addr: the default gateway to add 445*0Sstevel@tonic-gate * output: int: 1 on success, 0 on failure 446*0Sstevel@tonic-gate */ 447*0Sstevel@tonic-gate 448*0Sstevel@tonic-gate int 449*0Sstevel@tonic-gate add_default_route(const char *ifname, struct in_addr *gateway_nbo) 450*0Sstevel@tonic-gate { 451*0Sstevel@tonic-gate if (strchr(ifname, ':') != NULL) /* see README */ 452*0Sstevel@tonic-gate return (1); 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gate return (update_default_route(ifname, RTM_ADD, gateway_nbo, RTF_UP)); 455*0Sstevel@tonic-gate } 456*0Sstevel@tonic-gate 457*0Sstevel@tonic-gate /* 458*0Sstevel@tonic-gate * del_default_route(): deletes the default route to the given gateway 459*0Sstevel@tonic-gate * 460*0Sstevel@tonic-gate * input: const char *: the name of the interface associated with the route 461*0Sstevel@tonic-gate * struct in_addr: if not INADDR_ANY, the default gateway to remove 462*0Sstevel@tonic-gate * output: int: 1 on success, 0 on failure 463*0Sstevel@tonic-gate */ 464*0Sstevel@tonic-gate 465*0Sstevel@tonic-gate int 466*0Sstevel@tonic-gate del_default_route(const char *ifname, struct in_addr *gateway_nbo) 467*0Sstevel@tonic-gate { 468*0Sstevel@tonic-gate if (strchr(ifname, ':') != NULL) 469*0Sstevel@tonic-gate return (1); 470*0Sstevel@tonic-gate 471*0Sstevel@tonic-gate if (gateway_nbo->s_addr == htonl(INADDR_ANY)) /* no router */ 472*0Sstevel@tonic-gate return (1); 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate return (update_default_route(ifname, RTM_DELETE, gateway_nbo, 0)); 475*0Sstevel@tonic-gate } 476*0Sstevel@tonic-gate 477*0Sstevel@tonic-gate /* 478*0Sstevel@tonic-gate * inactivity_shutdown(): shuts down agent if there are no interfaces to manage 479*0Sstevel@tonic-gate * 480*0Sstevel@tonic-gate * input: iu_tq_t *: unused 481*0Sstevel@tonic-gate * void *: unused 482*0Sstevel@tonic-gate * output: void 483*0Sstevel@tonic-gate */ 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate /* ARGSUSED */ 486*0Sstevel@tonic-gate void 487*0Sstevel@tonic-gate inactivity_shutdown(iu_tq_t *tqp, void *arg) 488*0Sstevel@tonic-gate { 489*0Sstevel@tonic-gate if (ifs_count() > 0) /* shouldn't happen, but... */ 490*0Sstevel@tonic-gate return; 491*0Sstevel@tonic-gate 492*0Sstevel@tonic-gate iu_stop_handling_events(eh, DHCP_REASON_INACTIVITY, NULL, NULL); 493*0Sstevel@tonic-gate } 494*0Sstevel@tonic-gate 495*0Sstevel@tonic-gate /* 496*0Sstevel@tonic-gate * graceful_shutdown(): shuts down the agent gracefully 497*0Sstevel@tonic-gate * 498*0Sstevel@tonic-gate * input: int: the signal that caused graceful_shutdown to be called 499*0Sstevel@tonic-gate * output: void 500*0Sstevel@tonic-gate */ 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate void 503*0Sstevel@tonic-gate graceful_shutdown(int sig) 504*0Sstevel@tonic-gate { 505*0Sstevel@tonic-gate iu_stop_handling_events(eh, sig, drain_script, NULL); 506*0Sstevel@tonic-gate } 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate /* 509*0Sstevel@tonic-gate * register_acknak(): registers dhcp_acknak() to be called back when ACK or 510*0Sstevel@tonic-gate * NAK packets are received on a given interface 511*0Sstevel@tonic-gate * 512*0Sstevel@tonic-gate * input: struct ifslist *: the interface to register for 513*0Sstevel@tonic-gate * output: int: 1 on success, 0 on failure 514*0Sstevel@tonic-gate */ 515*0Sstevel@tonic-gate 516*0Sstevel@tonic-gate int 517*0Sstevel@tonic-gate register_acknak(struct ifslist *ifsp) 518*0Sstevel@tonic-gate { 519*0Sstevel@tonic-gate iu_event_id_t ack_id, ack_bcast_id = -1; 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate /* 522*0Sstevel@tonic-gate * having an acknak id already registered isn't impossible; 523*0Sstevel@tonic-gate * handle the situation as gracefully as possible. 524*0Sstevel@tonic-gate */ 525*0Sstevel@tonic-gate 526*0Sstevel@tonic-gate if (ifsp->if_acknak_id != -1) { 527*0Sstevel@tonic-gate dhcpmsg(MSG_DEBUG, "register_acknak: acknak id pending, " 528*0Sstevel@tonic-gate "attempting to cancel"); 529*0Sstevel@tonic-gate if (unregister_acknak(ifsp) == 0) 530*0Sstevel@tonic-gate return (0); 531*0Sstevel@tonic-gate } 532*0Sstevel@tonic-gate 533*0Sstevel@tonic-gate switch (ifsp->if_state) { 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate case BOUND: 536*0Sstevel@tonic-gate case REBINDING: 537*0Sstevel@tonic-gate case RENEWING: 538*0Sstevel@tonic-gate 539*0Sstevel@tonic-gate ack_bcast_id = iu_register_event(eh, ifsp->if_sock_fd, POLLIN, 540*0Sstevel@tonic-gate dhcp_acknak, ifsp); 541*0Sstevel@tonic-gate 542*0Sstevel@tonic-gate if (ack_bcast_id == -1) { 543*0Sstevel@tonic-gate dhcpmsg(MSG_WARNING, "register_acknak: cannot " 544*0Sstevel@tonic-gate "register to receive socket broadcasts"); 545*0Sstevel@tonic-gate return (0); 546*0Sstevel@tonic-gate } 547*0Sstevel@tonic-gate 548*0Sstevel@tonic-gate ack_id = iu_register_event(eh, ifsp->if_sock_ip_fd, POLLIN, 549*0Sstevel@tonic-gate dhcp_acknak, ifsp); 550*0Sstevel@tonic-gate break; 551*0Sstevel@tonic-gate 552*0Sstevel@tonic-gate default: 553*0Sstevel@tonic-gate ack_id = iu_register_event(eh, ifsp->if_dlpi_fd, POLLIN, 554*0Sstevel@tonic-gate dhcp_acknak, ifsp); 555*0Sstevel@tonic-gate break; 556*0Sstevel@tonic-gate } 557*0Sstevel@tonic-gate 558*0Sstevel@tonic-gate if (ack_id == -1) { 559*0Sstevel@tonic-gate dhcpmsg(MSG_WARNING, "register_acknak: cannot register event"); 560*0Sstevel@tonic-gate (void) iu_unregister_event(eh, ack_bcast_id, NULL); 561*0Sstevel@tonic-gate return (0); 562*0Sstevel@tonic-gate } 563*0Sstevel@tonic-gate 564*0Sstevel@tonic-gate ifsp->if_acknak_id = ack_id; 565*0Sstevel@tonic-gate hold_ifs(ifsp); 566*0Sstevel@tonic-gate 567*0Sstevel@tonic-gate ifsp->if_acknak_bcast_id = ack_bcast_id; 568*0Sstevel@tonic-gate if (ifsp->if_acknak_bcast_id != -1) { 569*0Sstevel@tonic-gate hold_ifs(ifsp); 570*0Sstevel@tonic-gate dhcpmsg(MSG_DEBUG, "register_acknak: registered broadcast id " 571*0Sstevel@tonic-gate "%d", ack_bcast_id); 572*0Sstevel@tonic-gate } 573*0Sstevel@tonic-gate 574*0Sstevel@tonic-gate dhcpmsg(MSG_DEBUG, "register_acknak: registered acknak id %d", ack_id); 575*0Sstevel@tonic-gate return (1); 576*0Sstevel@tonic-gate } 577*0Sstevel@tonic-gate 578*0Sstevel@tonic-gate /* 579*0Sstevel@tonic-gate * unregister_acknak(): unregisters dhcp_acknak() to be called back 580*0Sstevel@tonic-gate * 581*0Sstevel@tonic-gate * input: struct ifslist *: the interface to unregister for 582*0Sstevel@tonic-gate * output: int: 1 on success, 0 on failure 583*0Sstevel@tonic-gate */ 584*0Sstevel@tonic-gate 585*0Sstevel@tonic-gate int 586*0Sstevel@tonic-gate unregister_acknak(struct ifslist *ifsp) 587*0Sstevel@tonic-gate { 588*0Sstevel@tonic-gate if (ifsp->if_acknak_id != -1) { 589*0Sstevel@tonic-gate 590*0Sstevel@tonic-gate if (iu_unregister_event(eh, ifsp->if_acknak_id, NULL) == 0) { 591*0Sstevel@tonic-gate dhcpmsg(MSG_DEBUG, "unregister_acknak: cannot " 592*0Sstevel@tonic-gate "unregister acknak id %d on %s", 593*0Sstevel@tonic-gate ifsp->if_acknak_id, ifsp->if_name); 594*0Sstevel@tonic-gate return (0); 595*0Sstevel@tonic-gate } 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate dhcpmsg(MSG_DEBUG, "unregister_acknak: unregistered acknak id " 598*0Sstevel@tonic-gate "%d", ifsp->if_acknak_id); 599*0Sstevel@tonic-gate 600*0Sstevel@tonic-gate ifsp->if_acknak_id = -1; 601*0Sstevel@tonic-gate (void) release_ifs(ifsp); 602*0Sstevel@tonic-gate } 603*0Sstevel@tonic-gate 604*0Sstevel@tonic-gate if (ifsp->if_acknak_bcast_id != -1) { 605*0Sstevel@tonic-gate 606*0Sstevel@tonic-gate if (iu_unregister_event(eh, ifsp->if_acknak_bcast_id, NULL) 607*0Sstevel@tonic-gate == 0) { 608*0Sstevel@tonic-gate dhcpmsg(MSG_DEBUG, "unregister_acknak: cannot " 609*0Sstevel@tonic-gate "unregister broadcast id %d on %s", 610*0Sstevel@tonic-gate ifsp->if_acknak_id, ifsp->if_name); 611*0Sstevel@tonic-gate return (0); 612*0Sstevel@tonic-gate } 613*0Sstevel@tonic-gate 614*0Sstevel@tonic-gate dhcpmsg(MSG_DEBUG, "unregister_acknak: unregistered " 615*0Sstevel@tonic-gate "broadcast id %d", ifsp->if_acknak_bcast_id); 616*0Sstevel@tonic-gate 617*0Sstevel@tonic-gate ifsp->if_acknak_bcast_id = -1; 618*0Sstevel@tonic-gate (void) release_ifs(ifsp); 619*0Sstevel@tonic-gate } 620*0Sstevel@tonic-gate 621*0Sstevel@tonic-gate return (1); 622*0Sstevel@tonic-gate } 623*0Sstevel@tonic-gate 624*0Sstevel@tonic-gate /* 625*0Sstevel@tonic-gate * bind_sock(): binds a socket to a given IP address and port number 626*0Sstevel@tonic-gate * 627*0Sstevel@tonic-gate * input: int: the socket to bind 628*0Sstevel@tonic-gate * in_port_t: the port number to bind to, host byte order 629*0Sstevel@tonic-gate * in_addr_t: the address to bind to, host byte order 630*0Sstevel@tonic-gate * output: int: 1 on success, 0 on failure 631*0Sstevel@tonic-gate */ 632*0Sstevel@tonic-gate 633*0Sstevel@tonic-gate int 634*0Sstevel@tonic-gate bind_sock(int fd, in_port_t port_hbo, in_addr_t addr_hbo) 635*0Sstevel@tonic-gate { 636*0Sstevel@tonic-gate struct sockaddr_in sin; 637*0Sstevel@tonic-gate int on = 1; 638*0Sstevel@tonic-gate 639*0Sstevel@tonic-gate (void) memset(&sin, 0, sizeof (struct sockaddr_in)); 640*0Sstevel@tonic-gate sin.sin_family = AF_INET; 641*0Sstevel@tonic-gate sin.sin_port = htons(port_hbo); 642*0Sstevel@tonic-gate sin.sin_addr.s_addr = htonl(addr_hbo); 643*0Sstevel@tonic-gate 644*0Sstevel@tonic-gate (void) setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (int)); 645*0Sstevel@tonic-gate 646*0Sstevel@tonic-gate return (bind(fd, (struct sockaddr *)&sin, sizeof (sin)) == 0); 647*0Sstevel@tonic-gate } 648*0Sstevel@tonic-gate 649*0Sstevel@tonic-gate /* 650*0Sstevel@tonic-gate * valid_hostname(): check whether a string is a valid hostname 651*0Sstevel@tonic-gate * 652*0Sstevel@tonic-gate * input: const char *: the string to verify as a hostname 653*0Sstevel@tonic-gate * output: boolean_t: B_TRUE if the string is a valid hostname 654*0Sstevel@tonic-gate * 655*0Sstevel@tonic-gate * Note that we accept both host names beginning with a digit and 656*0Sstevel@tonic-gate * those containing hyphens. Neither is strictly legal according 657*0Sstevel@tonic-gate * to the RFCs, but both are in common practice, so we endeavour 658*0Sstevel@tonic-gate * to not break what customers are using. 659*0Sstevel@tonic-gate */ 660*0Sstevel@tonic-gate 661*0Sstevel@tonic-gate static boolean_t 662*0Sstevel@tonic-gate valid_hostname(const char *hostname) 663*0Sstevel@tonic-gate { 664*0Sstevel@tonic-gate unsigned int i; 665*0Sstevel@tonic-gate 666*0Sstevel@tonic-gate for (i = 0; hostname[i] != '\0'; i++) { 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate if (isalpha(hostname[i]) || isdigit(hostname[i]) || 669*0Sstevel@tonic-gate (((hostname[i] == '-') || (hostname[i] == '.')) && (i > 0))) 670*0Sstevel@tonic-gate continue; 671*0Sstevel@tonic-gate 672*0Sstevel@tonic-gate return (B_FALSE); 673*0Sstevel@tonic-gate } 674*0Sstevel@tonic-gate 675*0Sstevel@tonic-gate return (i > 0); 676*0Sstevel@tonic-gate } 677*0Sstevel@tonic-gate 678*0Sstevel@tonic-gate /* 679*0Sstevel@tonic-gate * iffile_to_hostname(): return the hostname contained on a line of the form 680*0Sstevel@tonic-gate * 681*0Sstevel@tonic-gate * [ ^I]*inet[ ^I]+hostname[\n]*\0 682*0Sstevel@tonic-gate * 683*0Sstevel@tonic-gate * in the file located at the specified path 684*0Sstevel@tonic-gate * 685*0Sstevel@tonic-gate * input: const char *: the path of the file to look in for the hostname 686*0Sstevel@tonic-gate * output: const char *: the hostname at that path, or NULL on failure 687*0Sstevel@tonic-gate */ 688*0Sstevel@tonic-gate 689*0Sstevel@tonic-gate #define IFLINE_MAX 1024 /* maximum length of a hostname.<if> line */ 690*0Sstevel@tonic-gate 691*0Sstevel@tonic-gate const char * 692*0Sstevel@tonic-gate iffile_to_hostname(const char *path) 693*0Sstevel@tonic-gate { 694*0Sstevel@tonic-gate FILE *fp; 695*0Sstevel@tonic-gate static char ifline[IFLINE_MAX]; 696*0Sstevel@tonic-gate 697*0Sstevel@tonic-gate fp = fopen(path, "r"); 698*0Sstevel@tonic-gate if (fp == NULL) 699*0Sstevel@tonic-gate return (NULL); 700*0Sstevel@tonic-gate 701*0Sstevel@tonic-gate /* 702*0Sstevel@tonic-gate * /etc/hostname.<if> may contain multiple ifconfig commands, but each 703*0Sstevel@tonic-gate * such command is on a separate line (see the "while read ifcmds" code 704*0Sstevel@tonic-gate * in /etc/init.d/inetinit). Thus we will read the file a line at a 705*0Sstevel@tonic-gate * time, searching for a line of the form 706*0Sstevel@tonic-gate * 707*0Sstevel@tonic-gate * [ ^I]*inet[ ^I]+hostname[\n]*\0 708*0Sstevel@tonic-gate * 709*0Sstevel@tonic-gate * extract the host name from it, and check it for validity. 710*0Sstevel@tonic-gate */ 711*0Sstevel@tonic-gate while (fgets(ifline, sizeof (ifline), fp) != NULL) { 712*0Sstevel@tonic-gate char *p; 713*0Sstevel@tonic-gate 714*0Sstevel@tonic-gate if ((p = strstr(ifline, "inet")) != NULL) { 715*0Sstevel@tonic-gate if ((p != ifline) && !isspace(p[-1])) { 716*0Sstevel@tonic-gate (void) fclose(fp); 717*0Sstevel@tonic-gate return (NULL); 718*0Sstevel@tonic-gate } 719*0Sstevel@tonic-gate p += 4; /* skip over "inet" and expect spaces or tabs */ 720*0Sstevel@tonic-gate if ((*p == '\n') || (*p == '\0')) { 721*0Sstevel@tonic-gate (void) fclose(fp); 722*0Sstevel@tonic-gate return (NULL); 723*0Sstevel@tonic-gate } 724*0Sstevel@tonic-gate if (isspace(*p)) { 725*0Sstevel@tonic-gate char *nlptr; 726*0Sstevel@tonic-gate 727*0Sstevel@tonic-gate /* no need to read more of the file */ 728*0Sstevel@tonic-gate (void) fclose(fp); 729*0Sstevel@tonic-gate 730*0Sstevel@tonic-gate while (isspace(*p)) 731*0Sstevel@tonic-gate p++; 732*0Sstevel@tonic-gate if ((nlptr = strrchr(p, '\n')) != NULL) 733*0Sstevel@tonic-gate *nlptr = '\0'; 734*0Sstevel@tonic-gate if (strlen(p) > MAXHOSTNAMELEN) { 735*0Sstevel@tonic-gate dhcpmsg(MSG_WARNING, 736*0Sstevel@tonic-gate "iffile_to_hostname:" 737*0Sstevel@tonic-gate " host name too long"); 738*0Sstevel@tonic-gate return (NULL); 739*0Sstevel@tonic-gate } 740*0Sstevel@tonic-gate if (valid_hostname(p)) { 741*0Sstevel@tonic-gate return (p); 742*0Sstevel@tonic-gate } else { 743*0Sstevel@tonic-gate dhcpmsg(MSG_WARNING, 744*0Sstevel@tonic-gate "iffile_to_hostname:" 745*0Sstevel@tonic-gate " host name not valid"); 746*0Sstevel@tonic-gate return (NULL); 747*0Sstevel@tonic-gate } 748*0Sstevel@tonic-gate } else { 749*0Sstevel@tonic-gate (void) fclose(fp); 750*0Sstevel@tonic-gate return (NULL); 751*0Sstevel@tonic-gate } 752*0Sstevel@tonic-gate } 753*0Sstevel@tonic-gate } 754*0Sstevel@tonic-gate 755*0Sstevel@tonic-gate (void) fclose(fp); 756*0Sstevel@tonic-gate return (NULL); 757*0Sstevel@tonic-gate } 758