// // $Id: dhcping.c,v 1.1 2004/07/26 00:46:09 root Exp $ // /* * Copyright 2000, 2001, 2002 by Edwin Groothuis, edwin@mavetju.org * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include #include #include "dhcp_options.h" #define BUF_SIZ 256*256 #define MAX_OPTIONS 256 #define MAX_DATA 256 int offset=0; void addpacket(char *pktbuf,char *msgbuf,int size) { memcpy(pktbuf+offset,msgbuf,size); offset+=size; } void dhcp_setup(char *); int dhcp_read(void); void dhcp_close(void); void dhcp_dump(unsigned char *buffer,int size); void dhcp_inform(char *ipaddr,char *gwaddr,char *hardware); void dhcp_request(char *ipaddr,char *gwaddr,char *hardware); void dhcp_release(char *ipaddr,char *gwaddr,char *hardware); void dhcp_packet(int type,char *ciaddr,char *opt50,char *gwaddr,char *hardware); int dhcp_socket; struct sockaddr_in dhcp_to; int _serveripaddress; int inform,request,verbose,VERBOSE,quiet; char *ci,*gi,*server,*hw; unsigned char serveridentifier[4]; int maxwait=3; typedef struct optpack cmdlineopt; struct optpack { unsigned int option; char data[MAX_DATA]; } cmdlineopts[MAX_OPTIONS]; char sname[64]; unsigned int opt = 0; void doargs(int argc,char **argv) { char ch; inform=request=verbose=VERBOSE=quiet=0; ci=gi=server="0.0.0.0"; hw="00:00:00:00:00:00"; if (argc==1) { printf("dhcping -S sname -c ciaddr -g giaddr -h chaddr -r -s server -t maxwait -i -v -q -o option:data\n"); exit(1); } while ((ch = getopt(argc,argv,"c:o:S:g:h:iqrs:t:vV"))>0) { switch (ch) { case 'c': ci=optarg;break; case 'g': gi=optarg;break; case 'h': hw=optarg;break; case 'i': inform=1;break; case 'q': quiet=1;break; case 'r': request=1;break; case 's': server=optarg;break; case 't': maxwait=atoi(optarg);break; case 'v': verbose=1;break; case 'V': VERBOSE=1;break; case 'o': if (opt > MAX_OPTIONS) { printf ("Exceeded maximum options parameter(%d).\n", MAX_OPTIONS); break; } char x[100+MAX_DATA]; sprintf (x, "%%d:%%%ds", MAX_DATA); sscanf (optarg, x, &cmdlineopts[opt].option, cmdlineopts[opt].data); printf ("optarg: %s, opt: %d, cmd1: %d, cmd2: %s, x: %s" , optarg, opt, cmdlineopts[opt].option, cmdlineopts[opt++].data, x); break; case 'S': sscanf (optarg, "%63s", sname);break; } } if (request && inform) { fprintf(stderr,"Error: -r and -i are mutally exclusive.\n"); exit(1); } // DHCPREQUEST is by default. if (!inform) request=1; } int main(int argc,char **argv) { fd_set read; struct timeval timeout; int foundpacket=0; int returnvalue=0; if (geteuid()!=0) { printf("This program should only be run by root or be installed as setuid root.\n"); exit(1); } doargs(argc,argv); if (VERBOSE) puts("setup"); dhcp_setup(server); if (setuid(getuid())!=0) { perror("setuid"); printf("Can't drop privileges back to normal user, program aborted.\n"); exit(1); } if (inform) { if (VERBOSE) puts("inform"); dhcp_inform(ci,gi,hw); } if (request) { if (VERBOSE) puts("request"); dhcp_request(ci,gi,hw); } while (!foundpacket) { FD_ZERO(&read); FD_SET(dhcp_socket,&read); timeout.tv_sec=maxwait; timeout.tv_usec=0; if(select(dhcp_socket+1,&read,NULL,NULL,&timeout)<0) { perror("select"); exit(0); } if (FD_ISSET(dhcp_socket,&read)) { if (VERBOSE) puts("read"); /* If a expected packet was found, then also release it. */ if ((foundpacket=dhcp_read())!=0) { if (request) { if (VERBOSE) puts("release"); dhcp_release(ci,gi,hw); } } } else { if (!quiet) fprintf(stderr,"no answer\n"); returnvalue=1; foundpacket=1; } } if (VERBOSE) puts("close"); dhcp_close(); return returnvalue; } void dhcp_setup(char *serveripaddress) { struct servent *servent,*clientent; struct hostent *hostent; int flag; struct sockaddr_in name; /* // setup sending socket */ if ((servent=getservbyname("bootps",0))==NULL) { perror("getservbyname: bootps"); exit(1); } if ((hostent=gethostbyname(serveripaddress))==NULL) { perror("gethostbyname"); exit(1); } dhcp_to.sin_family=AF_INET; bcopy(hostent->h_addr,&dhcp_to.sin_addr.s_addr,hostent->h_length); _serveripaddress=ntohl(dhcp_to.sin_addr.s_addr); /* dhcp_to.sin_addr.s_addr=INADDR_BROADCAST; */ dhcp_to.sin_port=servent->s_port; if ((dhcp_socket=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))==-1) { perror("dhcp_socket/socket"); exit(1); } flag=1; if (setsockopt (dhcp_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof flag) < 0) { perror("dhcp_socket/setsockopt: SO_REUSEADDR"); exit(1); } if (setsockopt(dhcp_socket,SOL_SOCKET,SO_BROADCAST,(char *)&flag, sizeof flag) < 0) { perror ("dhcp_socket/setsockopt: SO_BROADCAST"); exit(1); } if ((clientent=getservbyname("bootpc",0))==NULL) { perror("getservbyname: bootpc"); exit(1); } name.sin_family = AF_INET; name.sin_port = clientent->s_port; name.sin_addr.s_addr = INADDR_ANY; /* name.sin_addr.s_addr = INADDR_NONE; */ memset (name.sin_zero, 0, sizeof (name.sin_zero)); if (bind (dhcp_socket, (struct sockaddr *)&name, sizeof name) < 0) { perror("bind"); exit(1); } } void dhcp_request(char *ipaddr,char *gwaddr,char *hardware) { dhcp_packet(3,ipaddr,ipaddr,gwaddr,hardware); } void dhcp_release(char *ipaddr,char *gwaddr,char *hardware) { dhcp_packet(7,ipaddr,NULL,gwaddr,hardware); } void dhcp_inform(char *ipaddr,char *gwaddr,char *hardware) { dhcp_packet(8,ipaddr,NULL,gwaddr,hardware); } void dhcp_packet(int type,char *ipaddr,char *opt50,char *gwaddr,char *hardware) { static time_t l=0; unsigned char msgbuf[BUF_SIZ]; unsigned char pktbuf[BUF_SIZ]; int ip[4],gw[4],hw[16],ip50[4]; int hwcount; sscanf(ipaddr,"%d.%d.%d.%d",&ip[0],&ip[1],&ip[2],&ip[3]); sscanf(gwaddr,"%d.%d.%d.%d",&gw[0],&gw[1],&gw[2],&gw[3]); if (opt50) sscanf(opt50,"%d.%d.%d.%d",&ip50[0],&ip50[1],&ip50[2],&ip50[3]); memset(&hw,0,sizeof(hw)); hwcount=sscanf(hardware,"%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x", &hw[0],&hw[1],&hw[2],&hw[3], &hw[4],&hw[5],&hw[6],&hw[7], &hw[8],&hw[9],&hw[10],&hw[11], &hw[12],&hw[13],&hw[14],&hw[15]); memset(msgbuf,0,sizeof(msgbuf)); sprintf(msgbuf,"\1\1%c%c",hwcount,0); addpacket(pktbuf,msgbuf,4); /* xid */ if (l>time(NULL)) l++; else l=time(NULL); memcpy(msgbuf,&l,4); addpacket(pktbuf,msgbuf,4); /* secs and flags */ memset(msgbuf,0,4); addpacket(pktbuf,msgbuf,4); /* sprintf(msgbuf,"%c%c",0x80,0x00); */ /* sprintf(msgbuf,"%c%c",0x00,0x00); */ /* addpacket(pktbuf,msgbuf,2); */ /* ciaddr */ memset(msgbuf,0,4); sprintf(msgbuf,"%c%c%c%c",ip[0],ip[1],ip[2],ip[3]); addpacket(pktbuf,msgbuf,4); /* yiaddr */ memset(msgbuf,0,4); addpacket(pktbuf,msgbuf,4); /* siaddr */ memset(msgbuf,0,4); addpacket(pktbuf,msgbuf,4); /* giaddr */ sprintf(msgbuf,"%c%c%c%c",gw[0],gw[1],gw[2],gw[3]); addpacket(pktbuf,msgbuf,4); /* chaddr */ sprintf(msgbuf,"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", hw[0],hw[1],hw[2],hw[3],hw[4],hw[5],hw[6],hw[7], hw[8],hw[9],hw[10],hw[11],hw[12],hw[13],hw[14],hw[15]); addpacket(pktbuf,msgbuf,16); /* sname */ memset(msgbuf,0,64); printf("hallo!!!\n"); if (strlen (sname) > 0) { sprintf (msgbuf, "%s", sname); } addpacket(pktbuf,msgbuf,64); /* file */ memset(msgbuf,0,128); addpacket(pktbuf,msgbuf,128); /* options */ { /* cookie */ sprintf(msgbuf,"%c%c%c%c",99,130,83,99); addpacket(pktbuf,msgbuf,4); /* dhcp-type */ sprintf(msgbuf,"%c%c%c",53,1,type); addpacket(pktbuf,msgbuf,3); /* Not for inform */ if (type!=8) { /* requested IP address */ if (opt50) { sprintf(msgbuf,"%c%c%c%c%c%c",50,4,ip50[0],ip50[1],ip50[2],ip50[3]); addpacket(pktbuf,msgbuf,6); } /* server-identifier */ if (serveridentifier[0]) { sprintf(msgbuf,"%c%c%c%c%c%c",54,4, serveridentifier[0],serveridentifier[1], serveridentifier[2],serveridentifier[3]); addpacket(pktbuf,msgbuf,6); } /* command line options */ while (opt--) { sprintf (msgbuf, "%c%c%s", cmdlineopts[opt].option, (char *)(strlen (cmdlineopts[opt].data) + 1), cmdlineopts[opt].data); addpacket(pktbuf, msgbuf, 2 + strlen (cmdlineopts[opt].data) + 1); } } /* client-identifier */ // sprintf(msgbuf,"%c%c%c%c%c%c%c%c",61,6, // hw[0],hw[1],hw[2],hw[3],hw[4],hw[5]); // addpacket(pktbuf,msgbuf,8); /* parameter request list */ if (type==8) { sprintf(msgbuf,"%c%c%c",55,1,1); addpacket(pktbuf,msgbuf,3); } /* end of options */ sprintf(msgbuf,"%c",255); addpacket(pktbuf,msgbuf,1); } dhcp_dump(pktbuf,offset); sendto(dhcp_socket,pktbuf,offset,0,(struct sockaddr *)&dhcp_to,sizeof(dhcp_to)); offset=0; } int dhcp_read(void) { unsigned char msgbuf[BUF_SIZ]; struct sockaddr_in fromsock; socklen_t fromlen=sizeof(fromsock); int addr; int i; i=recvfrom(dhcp_socket,msgbuf,BUF_SIZ,0,(struct sockaddr *)&fromsock,&fromlen); addr=ntohl(fromsock.sin_addr.s_addr); if (!quiet) { printf( "Got answer from: %d.%d.%d.%d\n", ( addr >> 24 ) & 0xFF, ( addr >> 16 ) & 0xFF, ( addr >> 8 ) & 0xFF, ( addr ) & 0xFF ); } if (_serveripaddress!=addr) { if (!quiet) fprintf(stderr,"received from %d.%d.%d.%d, expected from %d.%d.%d.%d\n", ( addr >> 24 ) & 0xFF, ( addr >> 16 ) & 0xFF, ( addr >> 8 ) & 0xFF, ( addr ) & 0xFF, ( _serveripaddress >> 24 )&0xFF,(_serveripaddress >> 16 )&0xFF, ( _serveripaddress >> 8 )&0xFF,(_serveripaddress )&0xFF ); return 0; } dhcp_dump(msgbuf,i); return 1; } void dhcp_dump(unsigned char *buffer,int size) { int j; if (VERBOSE) printf("packet %d bytes\n",size); if (!VERBOSE) return; // // Are you sure you want to see this? Try dhcpdump, which is better // suited for this kind of work... See http://www.mavetju.org // j=0; while (j