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