Annotation of embedaddon/dhcping/dhcping.c, revision 1.1
1.1 ! misho 1: //
! 2: // $Id: dhcping.c,v 1.3 2002/01/27 01:57:15 mavetju Exp $
! 3: //
! 4:
! 5: /*
! 6: * Copyright 2000, 2001, 2002 by Edwin Groothuis, edwin@mavetju.org
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: *
! 17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 27: * SUCH DAMAGE.
! 28: *
! 29: */
! 30:
! 31: #include <sys/types.h>
! 32: #include <sys/socket.h>
! 33: #include <sys/time.h>
! 34: #include <sys/uio.h>
! 35: #include <netinet/in.h>
! 36: #include <unistd.h>
! 37: #include <netdb.h>
! 38: #include <stdio.h>
! 39: #include <stdlib.h>
! 40: #include <string.h>
! 41: #include <time.h>
! 42:
! 43: #include "dhcp_options.h"
! 44:
! 45: #define BUF_SIZ 256*256
! 46:
! 47: int offset=0;
! 48: void addpacket(char *pktbuf,char *msgbuf,int size) {
! 49: memcpy(pktbuf+offset,msgbuf,size);
! 50: offset+=size;
! 51: }
! 52:
! 53: void dhcp_setup(char *);
! 54: int dhcp_read(void);
! 55: void dhcp_close(void);
! 56: void dhcp_dump(unsigned char *buffer,int size);
! 57: void dhcp_inform(char *ipaddr,char *gwaddr,char *hardware);
! 58: void dhcp_request(char *ipaddr,char *gwaddr,char *hardware);
! 59: void dhcp_release(char *ipaddr,char *gwaddr,char *hardware);
! 60: void dhcp_packet(int type,char *ciaddr,char *opt50,char *gwaddr,char *hardware);
! 61:
! 62: int dhcp_socket;
! 63: struct sockaddr_in dhcp_to;
! 64:
! 65: int _serveripaddress;
! 66:
! 67: int inform,request,verbose,VERBOSE,quiet;
! 68: char *ci,*gi,*server,*hw;
! 69: unsigned char serveridentifier[4];
! 70: int maxwait=3;
! 71:
! 72: void doargs(int argc,char **argv) {
! 73: char ch;
! 74:
! 75: inform=request=verbose=VERBOSE=quiet=0;
! 76: ci=gi=server="0.0.0.0";
! 77: hw="00:00:00:00:00:00";
! 78:
! 79: if (argc==1) {
! 80: printf("dhcping -c ciaddr -g giaddr -h chaddr -r -s server -t maxwait -i -v -q\n");
! 81: exit(1);
! 82: }
! 83:
! 84: while ((ch = getopt(argc,argv,"c:g:h:iqrs:t:vV"))>0) {
! 85: switch (ch) {
! 86: case 'c': ci=optarg;break;
! 87: case 'g': gi=optarg;break;
! 88: case 'h': hw=optarg;break;
! 89: case 'i': inform=1;break;
! 90: case 'q': quiet=1;break;
! 91: case 'r': request=1;break;
! 92: case 's': server=optarg;break;
! 93: case 't': maxwait=atoi(optarg);break;
! 94: case 'v': verbose=1;break;
! 95: case 'V': VERBOSE=1;break;
! 96: }
! 97: }
! 98:
! 99: if (request && inform) {
! 100: fprintf(stderr,"Error: -r and -i are mutally exclusive.\n");
! 101: exit(1);
! 102: }
! 103:
! 104: // DHCPREQUEST is by default.
! 105: if (!inform) request=1;
! 106: }
! 107:
! 108: int main(int argc,char **argv) {
! 109: fd_set read;
! 110: struct timeval timeout;
! 111: int foundpacket=0;
! 112: int returnvalue=0;
! 113:
! 114: if (geteuid()!=0) {
! 115: printf("This program should only be ran by root or be installed as setuid root.\n");
! 116: exit(1);
! 117: }
! 118:
! 119: doargs(argc,argv);
! 120:
! 121: if (VERBOSE) puts("setup");
! 122: dhcp_setup(server);
! 123:
! 124: if (setuid(getuid())!=0) {
! 125: perror("setuid");
! 126: printf("Can't drop privileges back to normal user, program aborted.\n");
! 127: exit(1);
! 128: }
! 129:
! 130: if (inform) {
! 131: if (VERBOSE) puts("inform");
! 132: dhcp_inform(ci,gi,hw);
! 133: }
! 134: if (request) {
! 135: if (VERBOSE) puts("request");
! 136: dhcp_request(ci,gi,hw);
! 137: }
! 138:
! 139: while (!foundpacket) {
! 140: FD_ZERO(&read);
! 141: FD_SET(dhcp_socket,&read);
! 142: timeout.tv_sec=maxwait;
! 143: timeout.tv_usec=0;
! 144: if(select(dhcp_socket+1,&read,NULL,NULL,&timeout)<0) {
! 145: perror("select");
! 146: exit(0);
! 147: }
! 148: if (FD_ISSET(dhcp_socket,&read)) {
! 149: if (VERBOSE) puts("read");
! 150: /* If a expected packet was found, then also release it. */
! 151: if ((foundpacket=dhcp_read())!=0) {
! 152: if (request) {
! 153: if (VERBOSE) puts("release");
! 154: dhcp_release(ci,gi,hw);
! 155: }
! 156: }
! 157: } else {
! 158: if (!quiet)
! 159: fprintf(stderr,"no answer\n");
! 160: returnvalue=1;
! 161: foundpacket=1;
! 162: }
! 163: }
! 164: if (VERBOSE) puts("close");
! 165: dhcp_close();
! 166: return returnvalue;
! 167: }
! 168:
! 169:
! 170: void dhcp_setup(char *serveripaddress) {
! 171: struct servent *servent,*clientent;
! 172: struct hostent *hostent;
! 173: int flag;
! 174: struct sockaddr_in name;
! 175:
! 176: /*
! 177: // setup sending socket
! 178: */
! 179: if ((servent=getservbyname("bootps",0))==NULL) {
! 180: perror("getservbyname: bootps");
! 181: exit(1);
! 182: }
! 183: if ((hostent=gethostbyname(serveripaddress))==NULL) {
! 184: perror("gethostbyname");
! 185: exit(1);
! 186: }
! 187:
! 188: dhcp_to.sin_family=AF_INET;
! 189: bcopy(hostent->h_addr,&dhcp_to.sin_addr.s_addr,hostent->h_length);
! 190: _serveripaddress=ntohl(dhcp_to.sin_addr.s_addr);
! 191: /* dhcp_to.sin_addr.s_addr=INADDR_BROADCAST; */
! 192: dhcp_to.sin_port=servent->s_port;
! 193:
! 194: if ((dhcp_socket=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))==-1) {
! 195: perror("dhcp_socket/socket");
! 196: exit(1);
! 197: }
! 198:
! 199: flag=1;
! 200: if (setsockopt (dhcp_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof flag) < 0) {
! 201: perror("dhcp_socket/setsockopt: SO_REUSEADDR");
! 202: exit(1);
! 203: }
! 204:
! 205: if (setsockopt(dhcp_socket,SOL_SOCKET,SO_BROADCAST,(char *)&flag, sizeof flag) < 0) {
! 206: perror ("dhcp_socket/setsockopt: SO_BROADCAST");
! 207: exit(1);
! 208: }
! 209:
! 210: if ((clientent=getservbyname("bootpc",0))==NULL) {
! 211: perror("getservbyname: bootpc");
! 212: exit(1);
! 213: }
! 214: name.sin_family = AF_INET;
! 215: name.sin_port = clientent->s_port;
! 216: name.sin_addr.s_addr = INADDR_ANY;
! 217: /* name.sin_addr.s_addr = INADDR_NONE; */
! 218: memset (name.sin_zero, 0, sizeof (name.sin_zero));
! 219:
! 220: if (bind (dhcp_socket, (struct sockaddr *)&name, sizeof name) < 0) {
! 221: perror("bind");
! 222: exit(1);
! 223: }
! 224: }
! 225:
! 226: void dhcp_request(char *ipaddr,char *gwaddr,char *hardware) {
! 227: dhcp_packet(3,ipaddr,ipaddr,gwaddr,hardware);
! 228: }
! 229: void dhcp_release(char *ipaddr,char *gwaddr,char *hardware) {
! 230: dhcp_packet(7,ipaddr,NULL,gwaddr,hardware);
! 231: }
! 232: void dhcp_inform(char *ipaddr,char *gwaddr,char *hardware) {
! 233: dhcp_packet(8,ipaddr,NULL,gwaddr,hardware);
! 234: }
! 235:
! 236:
! 237: void dhcp_packet(int type,char *ipaddr,char *opt50,char *gwaddr,char *hardware) {
! 238: static time_t l=0;
! 239: unsigned char msgbuf[BUF_SIZ];
! 240: unsigned char pktbuf[BUF_SIZ];
! 241: int ip[4],gw[4],hw[16],ip50[4];
! 242: int hwcount;
! 243:
! 244: sscanf(ipaddr,"%d.%d.%d.%d",&ip[0],&ip[1],&ip[2],&ip[3]);
! 245: sscanf(gwaddr,"%d.%d.%d.%d",&gw[0],&gw[1],&gw[2],&gw[3]);
! 246: if (opt50)
! 247: sscanf(opt50,"%d.%d.%d.%d",&ip50[0],&ip50[1],&ip50[2],&ip50[3]);
! 248: memset(&hw,0,sizeof(hw));
! 249: hwcount=sscanf(hardware,"%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x",
! 250: &hw[0],&hw[1],&hw[2],&hw[3],
! 251: &hw[4],&hw[5],&hw[6],&hw[7],
! 252: &hw[8],&hw[9],&hw[10],&hw[11],
! 253: &hw[12],&hw[13],&hw[14],&hw[15]);
! 254:
! 255: memset(msgbuf,0,sizeof(msgbuf));
! 256: sprintf(msgbuf,"\1\1%c%c",hwcount,0);
! 257: addpacket(pktbuf,msgbuf,4);
! 258:
! 259: /* xid */
! 260: if (l>time(NULL))
! 261: l++;
! 262: else
! 263: l=time(NULL);
! 264: memcpy(msgbuf,&l,4);
! 265: addpacket(pktbuf,msgbuf,4);
! 266:
! 267: /* secs and flags */
! 268: memset(msgbuf,0,4);
! 269: addpacket(pktbuf,msgbuf,4);
! 270: /* sprintf(msgbuf,"%c%c",0x80,0x00); */
! 271: /* sprintf(msgbuf,"%c%c",0x00,0x00); */
! 272: /* addpacket(pktbuf,msgbuf,2); */
! 273:
! 274: /* ciaddr */
! 275: memset(msgbuf,0,4);
! 276: sprintf(msgbuf,"%c%c%c%c",ip[0],ip[1],ip[2],ip[3]);
! 277: addpacket(pktbuf,msgbuf,4);
! 278:
! 279: /* yiaddr */
! 280: memset(msgbuf,0,4);
! 281: addpacket(pktbuf,msgbuf,4);
! 282:
! 283: /* siaddr */
! 284: memset(msgbuf,0,4);
! 285: addpacket(pktbuf,msgbuf,4);
! 286:
! 287: /* giaddr */
! 288: sprintf(msgbuf,"%c%c%c%c",gw[0],gw[1],gw[2],gw[3]);
! 289: addpacket(pktbuf,msgbuf,4);
! 290:
! 291: /* chaddr */
! 292: sprintf(msgbuf,"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
! 293: hw[0],hw[1],hw[2],hw[3],hw[4],hw[5],hw[6],hw[7],
! 294: hw[8],hw[9],hw[10],hw[11],hw[12],hw[13],hw[14],hw[15]);
! 295: addpacket(pktbuf,msgbuf,16);
! 296:
! 297: /* sname */
! 298: memset(msgbuf,0,64);
! 299: addpacket(pktbuf,msgbuf,64);
! 300:
! 301: /* file */
! 302: memset(msgbuf,0,128);
! 303: addpacket(pktbuf,msgbuf,128);
! 304:
! 305: /* options */
! 306: {
! 307: /* cookie */
! 308: sprintf(msgbuf,"%c%c%c%c",99,130,83,99);
! 309: addpacket(pktbuf,msgbuf,4);
! 310:
! 311: /* dhcp-type */
! 312: sprintf(msgbuf,"%c%c%c",53,1,type);
! 313: addpacket(pktbuf,msgbuf,3);
! 314:
! 315: /* Not for inform */
! 316: if (type!=8) {
! 317: /* requested IP address */
! 318: if (opt50) {
! 319: sprintf(msgbuf,"%c%c%c%c%c%c",50,4,ip50[0],ip50[1],ip50[2],ip50[3]);
! 320: addpacket(pktbuf,msgbuf,6);
! 321: }
! 322:
! 323: /* server-identifier */
! 324: if (serveridentifier[0]) {
! 325: sprintf(msgbuf,"%c%c%c%c%c%c",54,4,
! 326: serveridentifier[0],serveridentifier[1],
! 327: serveridentifier[2],serveridentifier[3]);
! 328: addpacket(pktbuf,msgbuf,6);
! 329: }
! 330: }
! 331:
! 332: /* client-identifier */
! 333: // sprintf(msgbuf,"%c%c%c%c%c%c%c%c",61,6,
! 334: // hw[0],hw[1],hw[2],hw[3],hw[4],hw[5]);
! 335: // addpacket(pktbuf,msgbuf,8);
! 336:
! 337: /* parameter request list */
! 338: if (type==8) {
! 339: sprintf(msgbuf,"%c%c%c",55,1,1);
! 340: addpacket(pktbuf,msgbuf,3);
! 341: }
! 342:
! 343: /* end of options */
! 344: sprintf(msgbuf,"%c",255);
! 345: addpacket(pktbuf,msgbuf,1);
! 346: }
! 347:
! 348: dhcp_dump(pktbuf,offset);
! 349:
! 350: sendto(dhcp_socket,pktbuf,offset,0,(struct sockaddr *)&dhcp_to,sizeof(dhcp_to));
! 351:
! 352: offset=0;
! 353: }
! 354:
! 355:
! 356: int dhcp_read(void) {
! 357: unsigned char msgbuf[BUF_SIZ];
! 358: struct sockaddr_in fromsock;
! 359: socklen_t fromlen=sizeof(fromsock);
! 360: int addr;
! 361: int i;
! 362:
! 363: i=recvfrom(dhcp_socket,msgbuf,BUF_SIZ,0,(struct sockaddr *)&fromsock,&fromlen);
! 364: addr=ntohl(fromsock.sin_addr.s_addr);
! 365:
! 366: if (!quiet) {
! 367: printf( "Got answer from: %d.%d.%d.%d\n",
! 368: ( addr >> 24 ) & 0xFF, ( addr >> 16 ) & 0xFF,
! 369: ( addr >> 8 ) & 0xFF, ( addr ) & 0xFF
! 370: );
! 371: }
! 372:
! 373: if (_serveripaddress!=addr) {
! 374: if (!quiet)
! 375: fprintf(stderr,"received from %d.%d.%d.%d, expected from %d.%d.%d.%d\n",
! 376: ( addr >> 24 ) & 0xFF, ( addr >> 16 ) & 0xFF,
! 377: ( addr >> 8 ) & 0xFF, ( addr ) & 0xFF,
! 378: ( _serveripaddress >> 24 )&0xFF,(_serveripaddress >> 16 )&0xFF,
! 379: ( _serveripaddress >> 8 )&0xFF,(_serveripaddress )&0xFF
! 380: );
! 381: return 0;
! 382:
! 383: }
! 384:
! 385:
! 386: dhcp_dump(msgbuf,i);
! 387: return 1;
! 388: }
! 389:
! 390:
! 391:
! 392: void dhcp_dump(unsigned char *buffer,int size) {
! 393: int j;
! 394:
! 395: if (VERBOSE)
! 396: printf("packet %d bytes\n",size);
! 397:
! 398: if (!VERBOSE)
! 399: return;
! 400:
! 401: //
! 402: // Are you sure you want to see this? Try dhcpdump, which is better
! 403: // suited for this kind of work... See http://www.mavetju.org
! 404: //
! 405: j=0;
! 406: while (j<size) {
! 407: printf("%02x ",buffer[j]);
! 408: if (j%16==15) printf("\n");
! 409: j++;
! 410: }
! 411: printf("\n");
! 412:
! 413: printf("op: %d\n",buffer[0]);
! 414: printf("htype: %d\n",buffer[1]);
! 415: printf("hlen: %d\n",buffer[2]);
! 416: printf("hops: %d\n",buffer[3]);
! 417:
! 418: printf("xid: %02x%02x%02x%02x\n",
! 419: buffer[4],buffer[5],buffer[6],buffer[7]);
! 420: printf("secs: %d\n",255*buffer[8]+buffer[9]);
! 421: printf("flags: %x\n",255*buffer[10]+buffer[11]);
! 422:
! 423: printf("ciaddr: %d.%d.%d.%d\n",
! 424: buffer[12],buffer[13],buffer[14],buffer[15]);
! 425: printf("yiaddr: %d.%d.%d.%d\n",
! 426: buffer[16],buffer[17],buffer[18],buffer[19]);
! 427: printf("siaddr: %d.%d.%d.%d\n",
! 428: buffer[20],buffer[21],buffer[22],buffer[23]);
! 429: printf("giaddr: %d.%d.%d.%d\n",
! 430: buffer[24],buffer[25],buffer[26],buffer[27]);
! 431: printf("chaddr: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
! 432: buffer[28],buffer[29],buffer[30],buffer[31],
! 433: buffer[32],buffer[33],buffer[34],buffer[35],
! 434: buffer[36],buffer[37],buffer[38],buffer[39],
! 435: buffer[40],buffer[41],buffer[42],buffer[43]);
! 436: printf("sname : %s.\n",buffer+44);
! 437: printf("fname : %s.\n",buffer+108);
! 438:
! 439: j=236;
! 440: j+=4; /* cookie */
! 441: while (j<size && buffer[j]!=255) {
! 442: printf("option %d %s\n",buffer[j],dhcp_options[buffer[j]]);
! 443:
! 444: switch (buffer[j]) {
! 445: case 1:
! 446: printf("\tSubnet mask: %d.%d.%d.%d\n",
! 447: buffer[j+2],buffer[j+3],buffer[j+4],buffer[j+5]);
! 448: break;
! 449: case 3:
! 450: printf("\tRouter: %d.%d.%d.%d\n",
! 451: buffer[j+2],buffer[j+3],buffer[j+4],buffer[j+5]);
! 452: break;
! 453: case 50:
! 454: printf("\tRequested IP address: %d.%d.%d.%d\n",
! 455: buffer[j+2],buffer[j+3],buffer[j+4],buffer[j+5]);
! 456: break;
! 457: case 53:
! 458: printf("\tDHCP message type: %d (%s)\n",
! 459: buffer[j+2],dhcp_message_types[buffer[j+2]]);
! 460: break;
! 461: case 54:
! 462: memcpy(serveridentifier,buffer+j+2,4);
! 463: printf("\tServer identifier: %d.%d.%d.%d\n",
! 464: serveridentifier[0],serveridentifier[1],
! 465: serveridentifier[2],serveridentifier[3]);
! 466: break;
! 467: case 61:
! 468: printf("\tClient identifier: %02x%02x%02x%02x%02x%02x\n",
! 469: buffer[j+2],buffer[j+3],buffer[j+4],
! 470: buffer[j+5],buffer[j+6],buffer[j+7]);
! 471: break;
! 472: }
! 473:
! 474: /*
! 475: // This might go wrong if a mallformed packet is received.
! 476: // Maybe from a bogus server which is instructed to reply
! 477: // with invalid data and thus causing an exploit.
! 478: // My head hurts... but I think it's solved by the checking
! 479: // for j<size at the begin of the while-loop.
! 480: */
! 481: j+=buffer[j+1]+2;
! 482: }
! 483: }
! 484:
! 485:
! 486: void dhcp_close(void) {
! 487: close(dhcp_socket);
! 488: }
! 489:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>