Home | History | Annotate | Download | only in dhc
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the License).
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/CDDL.txt
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/CDDL.txt.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets [] replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  *
     26  */
     27 
     28 #pragma ident	"@(#)dhcpc.c	1.7	07/07/31 SMI"
     29 
     30 #include <sys/types.h>
     31 #include <poll.h>
     32 #include <stdlib.h>
     33 #include <strings.h>
     34 #include <stdio.h>
     35 #include <ctype.h>
     36 #include <unistd.h>
     37 #include <sys/socket.h>
     38 #include <arpa/inet.h>
     39 #include <errno.h>
     40 
     41 #include "dhcp.h"
     42 
     43 static int iHelp = 0;
     44 static int iReuse = 0;
     45 static int iVerbose = 0;
     46 static int iSeconds = 10;
     47 static char pcHWClass[1024] = "";
     48 
     49 
     50 #define	QTYPE_MAC	1
     51 /*
     52 #define	QTYPE_IP	2
     53 #define	QTYPE_HOSTNAME	3
     54 #define	QTYPE_IFNUMBER	4
     55 
     56 static int iQifnumber;
     57 static unsigned char pucQIP[4];
     58 static char pcQhostname[1024];
     59 */
     60 
     61 static int iQType = -1;
     62 static unsigned char pucQMAC[6];
     63 
     64 static char *ppcHWClasses[4] = {
     65 	"",
     66 	"SUNW.UltraSPARC-IIi-cEngine",
     67 	"SUNW.Ultra-5_10",
     68 	"SUNW.Ultra-60"};
     69 
     70 void
     71 vHelp(void)
     72 {
     73 	(void) printf("usage: dhcpc [-q MAC] [-r] [-t secs] [-v] [-c class] "
     74 				"[-?] [-h]\n");
     75 	(void) printf("          -h or -? or no parameters to request this "
     76 				"help.\n");
     77 	(void) printf("          -q To specify the request.\n");
     78 	(void) printf("             Format is XX:XX:XX:XX:XX:XX. Not "
     79 				"neccesary two Xs.\n");
     80 	(void) printf("             Not neccesary uppercase nor lowercase.\n");
     81 	(void) printf("          -r Use SO_REUSEADDR (see man getsockopt). "
     82 				"Default no.\n");
     83 	(void) printf("          -t To specify seconds to sniff answers. "
     84 				"Default 10.\n");
     85 	(void) printf("          -v Verbose report.\n");
     86 	(void) printf("          -c To specify the class.\n");
     87 	(void) printf("             A number will specify the class from "
     88 				"this table:\n");
     89 	(void) printf("               1: SUNW.UltraSPARC-IIi-cEngine\n");
     90 	(void) printf("               2: SUNW.Ultra-5_10\n");
     91 	(void) printf("               3: SUNW.Ultra-60\n");
     92 	(void) printf("             A higher number will disable the class "
     93 				"specification.\n");
     94 	(void) printf("             Anything else will be considered as the "
     95 				"class string.\n");
     96 	(void) printf("             If -c not specified, then \\0 will be "
     97 				"send as class.\n\n");
     98 	(void) printf("   WARNING: Please be sure to instruct the dhcp server "
     99 				"not to check\n");
    100 	(void) printf("            the IP address that is about to offer "
    101 				"using ICMP.\n");
    102 	(void) printf("            For Solaris DHCP daemon is option `-n`.\n");
    103 
    104 	exit(1);
    105 }
    106 
    107 int
    108 iStrTabIPv4(char *pcStr)
    109 {
    110 	int iNum[4];
    111 	char pcAux[128];
    112 	char *pcAux2;
    113 
    114 	(void) strlcpy(pcAux, pcStr, 128);
    115 	pcAux2 = strchr(pcAux, '.');
    116 	if (!pcAux2)
    117 		return (-1);
    118 	*pcAux2 = 0;
    119 	iNum[0] = atoi(pcAux);
    120 
    121 	(void) strcpy(pcAux, pcAux2+1);
    122 	pcAux2 = strchr(pcAux, '.');
    123 	if (!pcAux2)
    124 		return (-1);
    125 	*pcAux2 = 0;
    126 	iNum[1] = atoi(pcAux);
    127 
    128 	(void) strcpy(pcAux, pcAux2+1);
    129 	pcAux2 = strchr(pcAux, '.');
    130 	if (!pcAux2)
    131 		return (-1);
    132 	*pcAux2 = 0;
    133 	iNum[2] = atoi(pcAux);
    134 
    135 	iNum[3] = atoi(pcAux2+1);
    136 
    137 	(void) sprintf(pcStr, "%3d.%3d.%3d.%3d", iNum[0], iNum[1], iNum[2],
    138 				iNum[3]);
    139 	return (0);
    140 }
    141 
    142 static int
    143 iCountChar(char *txt, char c)
    144 {
    145 	int i = 0;
    146 	do {
    147 		txt = strchr(txt, (int)c);
    148 		if (txt) { i++; txt++; }
    149 	} while (txt);
    150 	return (i);
    151 }
    152 
    153 static int
    154 iGetHexVal(char c)
    155 {
    156 	c = (char)toupper(c);
    157 	switch (c) {
    158 		case '0':	case '1':	case '2':	case '3':
    159 		case '4':	case '5':	case '6':	case '7':
    160 		case '8':	case '9': return c-'0';
    161 		case 'A':	case 'B':	case 'C':	case 'D':
    162 		case 'E':	case 'F': return c-'A'+10;
    163 		default:;
    164 	};
    165 	return (-1);
    166 }
    167 
    168 /* xx:xx:xx:xx:xx:xx (not neccesarily two Xs per number) */
    169 static int
    170 iConvertMAC(char *opt, unsigned char *mac)
    171 {
    172 	int val;
    173 	int i;
    174 	for (i = 0; i < 6; i++) {
    175 		if (opt[0] == ':') {
    176 			mac[i] = 0;
    177 			opt++;
    178 			continue;
    179 		}
    180 		if (opt[1] == ':') {
    181 			val = iGetHexVal(opt[0]);
    182 			if (val == -1)
    183 				return (1);
    184 			mac[i] = (unsigned char) val;
    185 			opt += 2;
    186 			continue;
    187 			}
    188 		if ((opt[2] != ':') && (opt[2] != 0))
    189 			return (1);
    190 		val = iGetHexVal(opt[0]);
    191 		if (val == -1)
    192 			return (1);
    193 		mac[i] = (unsigned char) (val * 16);
    194 		val = iGetHexVal(opt[1]);
    195 		if (val == -1)
    196 			return (1);
    197 		mac[i] += (unsigned char) val;
    198 		opt += 3;
    199 	}
    200 	return (0);
    201 }
    202 
    203 void
    204 vParseParams(int nargs, char *arg[])
    205 {
    206 	extern char *optarg;
    207 	char c;
    208 
    209 	while ((c = (char)getopt(nargs, arg, "?hrq:vt:c:")) != EOF) {
    210 	switch (c) {
    211 		case 'q':
    212 			if (iCountChar(optarg, ':') == 5) {
    213 				iQType = QTYPE_MAC;
    214 				if (iConvertMAC(optarg, pucQMAC)) {
    215 					(void) printf("dhcpc: error parsing "
    216 						"mac address.\n");
    217 					iQType = -1;
    218 				}
    219 			}
    220 			break;
    221 		case 'r': iReuse = 1; break;
    222 		case 'v': iVerbose = 1; break;
    223 		case 't':
    224 			iSeconds = atoi(optarg);
    225 			if (!iSeconds)
    226 				iSeconds = 10;
    227 			break;
    228 		case 'c':
    229 			if (!atoi(optarg))
    230 				(void) strcpy(pcHWClass, optarg);
    231 			else {
    232 				if (atoi(optarg) < (int)sizeof (ppcHWClasses)
    233 					/ (int)sizeof (char *))
    234 					(void) strcpy(pcHWClass,
    235 						ppcHWClasses[atoi(optarg)]);
    236 			}
    237 			break;
    238 		case '?':
    239 		case 'h':
    240 		default : iHelp = 1; break;
    241 		}
    242 	}
    243 }
    244 
    245 int
    246 send_dhcp_packet(int fd, struct dhcpmsg *payload)
    247 {
    248 	struct sockaddr_in dest;
    249 	(void) memset(&dest, 0, sizeof (dest));
    250 	dest.sin_family = AF_INET;
    251 	dest.sin_port = htons(67);
    252 	dest.sin_addr.s_addr = htonl(INADDR_BROADCAST);
    253 	return sendto(fd, payload, sizeof (struct dhcpmsg), 0,
    254 			(struct sockaddr *)&dest, sizeof (dest));
    255 }
    256 
    257 
    258 static char *
    259 pcAddr2Str(unsigned long ul)
    260 {
    261 	static char buf[256];
    262 	(void) memset(buf, 0, 256);
    263 	(void) inet_ntop(AF_INET, &ul, buf, 255);
    264 	(void) iStrTabIPv4(buf);
    265 	return (buf);
    266 }
    267 
    268 static void
    269 vPrintDHCPMessage(struct dhcpmsg *m)
    270 {
    271 	(void) printf("SERVER: %s\t\tIP: %s\n",
    272 			m->sname, pcAddr2Str(m->yiaddr));
    273 	if (!iVerbose)
    274 		return;
    275 
    276 	(void) printf("   Opcode:                 %s\n",
    277 			(m->op == 1)?"BOOTREQUEST":"BOOTREPLY");
    278 	(void) printf("   HW Address Type:        %d\n", m->htype);
    279 	(void) printf("   HW Address Length:      %d\n", m->hlen);
    280 	(void) printf("   Hops:                   %d\n", m->hops);
    281 	(void) printf("   Transaction ID:         %ld\n", m->xid);
    282 	(void) printf("   Seconds:                %d\n", m->secs);
    283 	(void) printf("   Flags:                  0x%04x (%s)\n", m->flags,
    284 			(m->flags & htons(0x8000))?"BROADCAST":"UNICAST");
    285 	(void) printf("   Client IP Address:      %s\n", pcAddr2Str(m->ciaddr));
    286 	(void) printf("   Your IP Address:        %s\n", pcAddr2Str(m->yiaddr));
    287 	(void) printf("   Next Server IP Address: %s\n", pcAddr2Str(m->siaddr));
    288 	(void) printf("   Relay Agent IP Address: %s\n", pcAddr2Str(m->giaddr));
    289 	(void) printf("   Client HW Address:      "
    290 			"%02x:%02x:%02x:%02x:%02x:%02x\n",
    291 			m->chaddr[0], m->chaddr[1], m->chaddr[2], m->chaddr[3],
    292 			m->chaddr[4], m->chaddr[5]);
    293 	(void) printf("   Server Name:            %s\n", m->sname);
    294 	(void) printf("   Boot File Name:         %s\n", m->file);
    295 	(void) printf("   Options:\n");
    296 }
    297 
    298 int
    299 main(int nargs, char *arg[])
    300 {
    301 	time_t t1;
    302 	struct dhcpmsg dhcpm;
    303 	int len;
    304 	struct pollfd pfd;
    305 
    306 	int n;
    307 
    308 	vParseParams(nargs, arg);
    309 
    310 	(void) printf("\n");
    311 
    312 	if (iHelp) vHelp();
    313 	if (iQType == -1) vHelp();
    314 
    315 	n = iDHCPStart(NULL, 0, iReuse);
    316 	if (n < 0) {
    317 		(void) printf("dhcpc: error %d: %s\n",
    318 			errno, strerror(errno));	/*lint !e746 */
    319 		return (5);
    320 	}
    321 
    322 	vDHCPBuildDiscover(&dhcpm, pucQMAC, pcHWClass);
    323 
    324 	len = send_dhcp_packet(n, &dhcpm);
    325 	if (len <= 0) {
    326 		(void) printf("write on socket failed: %s", strerror(errno));
    327 		(void) close(n);
    328 		return (1);
    329 	}
    330 
    331 	t1 = time(NULL);
    332 	while (iSeconds > time(NULL)-t1) {
    333 
    334 		(void) memset(&pfd, 0, sizeof (pfd));
    335 		pfd.fd = n;
    336 		pfd.events = POLLIN;
    337 		len = poll(&pfd, 1, 1000);
    338 		if (!len) continue;
    339 
    340 		(void) recvfrom(n, (void *)&dhcpm, sizeof (dhcpm), 0, NULL,
    341 				NULL);
    342 		vPrintDHCPMessage(&dhcpm);
    343 	}
    344 
    345 	(void) close(n);
    346 
    347 	(void) printf("\n");
    348 
    349 	return (0);
    350 }
    351