ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/dhcpping/dhcping.c
Revision: 1.2
Committed: Mon Jul 26 02:49:32 2004 UTC (19 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +8 -8 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 //
2 root 1.2 // $Id: dhcping.c,v 1.1 2004/07/26 00:46:09 root Exp $
3 root 1.1 //
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 root 1.2 char format[100+MAX_DATA];
113     sprintf (format, "%%u:%%%ds", MAX_DATA);
114     sscanf (optarg, format, &cmdlineopts[opt].option, cmdlineopts[opt].data);
115     opt++;
116 root 1.1 break;
117     case 'S': sscanf (optarg, "%63s", sname);break;
118     }
119     }
120    
121     if (request && inform) {
122     fprintf(stderr,"Error: -r and -i are mutally exclusive.\n");
123     exit(1);
124     }
125    
126     // DHCPREQUEST is by default.
127     if (!inform) request=1;
128     }
129    
130     int main(int argc,char **argv) {
131     fd_set read;
132     struct timeval timeout;
133     int foundpacket=0;
134     int returnvalue=0;
135    
136     if (geteuid()!=0) {
137     printf("This program should only be run by root or be installed as setuid root.\n");
138     exit(1);
139     }
140    
141     doargs(argc,argv);
142    
143     if (VERBOSE) puts("setup");
144     dhcp_setup(server);
145    
146     if (setuid(getuid())!=0) {
147     perror("setuid");
148     printf("Can't drop privileges back to normal user, program aborted.\n");
149     exit(1);
150     }
151    
152     if (inform) {
153     if (VERBOSE) puts("inform");
154     dhcp_inform(ci,gi,hw);
155     }
156     if (request) {
157     if (VERBOSE) puts("request");
158     dhcp_request(ci,gi,hw);
159     }
160    
161     while (!foundpacket) {
162     FD_ZERO(&read);
163     FD_SET(dhcp_socket,&read);
164     timeout.tv_sec=maxwait;
165     timeout.tv_usec=0;
166     if(select(dhcp_socket+1,&read,NULL,NULL,&timeout)<0) {
167     perror("select");
168     exit(0);
169     }
170     if (FD_ISSET(dhcp_socket,&read)) {
171     if (VERBOSE) puts("read");
172     /* If a expected packet was found, then also release it. */
173     if ((foundpacket=dhcp_read())!=0) {
174     if (request) {
175     if (VERBOSE) puts("release");
176     dhcp_release(ci,gi,hw);
177     }
178     }
179     } else {
180     if (!quiet)
181     fprintf(stderr,"no answer\n");
182     returnvalue=1;
183     foundpacket=1;
184     }
185     }
186     if (VERBOSE) puts("close");
187     dhcp_close();
188     return returnvalue;
189     }
190    
191    
192     void dhcp_setup(char *serveripaddress) {
193     struct servent *servent,*clientent;
194     struct hostent *hostent;
195     int flag;
196     struct sockaddr_in name;
197    
198     /*
199     // setup sending socket
200     */
201     if ((servent=getservbyname("bootps",0))==NULL) {
202     perror("getservbyname: bootps");
203     exit(1);
204     }
205     if ((hostent=gethostbyname(serveripaddress))==NULL) {
206     perror("gethostbyname");
207     exit(1);
208     }
209    
210     dhcp_to.sin_family=AF_INET;
211     bcopy(hostent->h_addr,&dhcp_to.sin_addr.s_addr,hostent->h_length);
212     _serveripaddress=ntohl(dhcp_to.sin_addr.s_addr);
213     /* dhcp_to.sin_addr.s_addr=INADDR_BROADCAST; */
214     dhcp_to.sin_port=servent->s_port;
215    
216     if ((dhcp_socket=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))==-1) {
217     perror("dhcp_socket/socket");
218     exit(1);
219     }
220    
221     flag=1;
222     if (setsockopt (dhcp_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof flag) < 0) {
223     perror("dhcp_socket/setsockopt: SO_REUSEADDR");
224     exit(1);
225     }
226    
227     if (setsockopt(dhcp_socket,SOL_SOCKET,SO_BROADCAST,(char *)&flag, sizeof flag) < 0) {
228     perror ("dhcp_socket/setsockopt: SO_BROADCAST");
229     exit(1);
230     }
231    
232     if ((clientent=getservbyname("bootpc",0))==NULL) {
233     perror("getservbyname: bootpc");
234     exit(1);
235     }
236     name.sin_family = AF_INET;
237     name.sin_port = clientent->s_port;
238     name.sin_addr.s_addr = INADDR_ANY;
239     /* name.sin_addr.s_addr = INADDR_NONE; */
240     memset (name.sin_zero, 0, sizeof (name.sin_zero));
241    
242     if (bind (dhcp_socket, (struct sockaddr *)&name, sizeof name) < 0) {
243     perror("bind");
244     exit(1);
245     }
246     }
247    
248     void dhcp_request(char *ipaddr,char *gwaddr,char *hardware) {
249     dhcp_packet(3,ipaddr,ipaddr,gwaddr,hardware);
250     }
251     void dhcp_release(char *ipaddr,char *gwaddr,char *hardware) {
252     dhcp_packet(7,ipaddr,NULL,gwaddr,hardware);
253     }
254     void dhcp_inform(char *ipaddr,char *gwaddr,char *hardware) {
255     dhcp_packet(8,ipaddr,NULL,gwaddr,hardware);
256     }
257    
258    
259     void dhcp_packet(int type,char *ipaddr,char *opt50,char *gwaddr,char *hardware) {
260     static time_t l=0;
261     unsigned char msgbuf[BUF_SIZ];
262     unsigned char pktbuf[BUF_SIZ];
263     int ip[4],gw[4],hw[16],ip50[4];
264     int hwcount;
265    
266     sscanf(ipaddr,"%d.%d.%d.%d",&ip[0],&ip[1],&ip[2],&ip[3]);
267     sscanf(gwaddr,"%d.%d.%d.%d",&gw[0],&gw[1],&gw[2],&gw[3]);
268     if (opt50)
269     sscanf(opt50,"%d.%d.%d.%d",&ip50[0],&ip50[1],&ip50[2],&ip50[3]);
270     memset(&hw,0,sizeof(hw));
271     hwcount=sscanf(hardware,"%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x",
272     &hw[0],&hw[1],&hw[2],&hw[3],
273     &hw[4],&hw[5],&hw[6],&hw[7],
274     &hw[8],&hw[9],&hw[10],&hw[11],
275     &hw[12],&hw[13],&hw[14],&hw[15]);
276    
277     memset(msgbuf,0,sizeof(msgbuf));
278     sprintf(msgbuf,"\1\1%c%c",hwcount,0);
279     addpacket(pktbuf,msgbuf,4);
280    
281     /* xid */
282     if (l>time(NULL))
283     l++;
284     else
285     l=time(NULL);
286     memcpy(msgbuf,&l,4);
287     addpacket(pktbuf,msgbuf,4);
288    
289     /* secs and flags */
290     memset(msgbuf,0,4);
291     addpacket(pktbuf,msgbuf,4);
292     /* sprintf(msgbuf,"%c%c",0x80,0x00); */
293     /* sprintf(msgbuf,"%c%c",0x00,0x00); */
294     /* addpacket(pktbuf,msgbuf,2); */
295    
296     /* ciaddr */
297     memset(msgbuf,0,4);
298     sprintf(msgbuf,"%c%c%c%c",ip[0],ip[1],ip[2],ip[3]);
299     addpacket(pktbuf,msgbuf,4);
300    
301     /* yiaddr */
302     memset(msgbuf,0,4);
303     addpacket(pktbuf,msgbuf,4);
304    
305     /* siaddr */
306     memset(msgbuf,0,4);
307     addpacket(pktbuf,msgbuf,4);
308    
309     /* giaddr */
310     sprintf(msgbuf,"%c%c%c%c",gw[0],gw[1],gw[2],gw[3]);
311     addpacket(pktbuf,msgbuf,4);
312    
313     /* chaddr */
314     sprintf(msgbuf,"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
315     hw[0],hw[1],hw[2],hw[3],hw[4],hw[5],hw[6],hw[7],
316     hw[8],hw[9],hw[10],hw[11],hw[12],hw[13],hw[14],hw[15]);
317     addpacket(pktbuf,msgbuf,16);
318    
319     /* sname */
320     memset(msgbuf,0,64);
321     printf("hallo!!!\n");
322     if (strlen (sname) > 0) {
323     sprintf (msgbuf, "%s", sname);
324     }
325     addpacket(pktbuf,msgbuf,64);
326    
327     /* file */
328     memset(msgbuf,0,128);
329     addpacket(pktbuf,msgbuf,128);
330    
331     /* options */
332     {
333     /* cookie */
334     sprintf(msgbuf,"%c%c%c%c",99,130,83,99);
335     addpacket(pktbuf,msgbuf,4);
336    
337     /* dhcp-type */
338     sprintf(msgbuf,"%c%c%c",53,1,type);
339     addpacket(pktbuf,msgbuf,3);
340    
341     /* Not for inform */
342     if (type!=8) {
343     /* requested IP address */
344     if (opt50) {
345     sprintf(msgbuf,"%c%c%c%c%c%c",50,4,ip50[0],ip50[1],ip50[2],ip50[3]);
346     addpacket(pktbuf,msgbuf,6);
347     }
348    
349     /* server-identifier */
350     if (serveridentifier[0]) {
351     sprintf(msgbuf,"%c%c%c%c%c%c",54,4,
352     serveridentifier[0],serveridentifier[1],
353     serveridentifier[2],serveridentifier[3]);
354     addpacket(pktbuf,msgbuf,6);
355     }
356     /* command line options */
357     while (opt--) {
358 root 1.2 sprintf (msgbuf, "%c%c", cmdlineopts[opt].option, (char *)(strlen (cmdlineopts[opt].data)));
359     memcpy (&msgbuf[2], cmdlineopts[opt].data, strlen (cmdlineopts[opt].data));
360     addpacket(pktbuf, msgbuf, 2 + strlen (cmdlineopts[opt].data));
361 root 1.1 }
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