Annotation of embedaddon/dhcping/dhcping.c, revision 1.1.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>