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

# Content
1 //
2 // $Id: dhcping.c,v 1.1 2004/07/26 00:46:09 root 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 format[100+MAX_DATA];
113 sprintf (format, "%%u:%%%ds", MAX_DATA);
114 sscanf (optarg, format, &cmdlineopts[opt].option, cmdlineopts[opt].data);
115 opt++;
116 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 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 }
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