File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcping / dhcping.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:27:53 2012 UTC (12 years, 3 months ago) by misho
Branches: dhcping, MAIN
CVS tags: v1_2, HEAD
dhcping

    1: //
    2: // $Id: dhcping.c,v 1.1.1.1 2012/02/21 22:27:53 misho 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>