ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/dhcpping/dhcping.c
Revision: 1.1
Committed: Mon Jul 26 00:46:09 2004 UTC (19 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Log Message:
*** empty log message ***

File Contents

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