~ubuntu-branches/ubuntu/precise/bootpc/precise

« back to all changes in this revision

Viewing changes to bootpc.c

  • Committer: Bazaar Package Importer
  • Author(s): Herbert Xu
  • Date: 2000-11-15 21:32:15 UTC
  • Revision ID: james.westby@ubuntu.com-20001115213215-fbob3f7gl5nb9vwm
Tags: upstream-0.64
ImportĀ upstreamĀ versionĀ 0.64

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  Last updated : Mon Sep 16 15:20:57 1996
 
3
  Modified by JSP from code by Charles Hawkins <ceh@eng.cam.ac.uk>,
 
4
 
 
5
    J.S.Peatfield@damtp.cam.ac.uk
 
6
 
 
7
  Copyright (c) University of Cambridge, 1993-1996
 
8
  See the file NOTICE for conditions of use and distribution.
 
9
 
 
10
  $Revision: 1.11 $
 
11
  $Date: 1998/12/15 03:42:28 $
 
12
*/
 
13
 
 
14
/* Standard headers */
 
15
#include <stdio.h>
 
16
#include <sys/types.h>
 
17
#include <sys/socket.h>
 
18
#include <sys/ioctl.h>
 
19
#include <sys/time.h>
 
20
#include <netinet/in.h>
 
21
#include <netinet/ip.h>
 
22
#include <netinet/ip_icmp.h>
 
23
#include <netdb.h>
 
24
#include <arpa/inet.h>
 
25
#include <net/if.h>
 
26
#include <net/if_arp.h>
 
27
#include <sys/time.h>
 
28
#include <unistd.h>
 
29
#include <string.h>
 
30
#include <stdlib.h>
 
31
#include <errno.h>
 
32
#include <ctype.h>
 
33
#include <resolv.h>
 
34
 
 
35
/* local headers */
 
36
#include "bootpc.h"
 
37
 
 
38
/* My global variables */
 
39
int bootp_verbose = 0 ;   /* verbose mode or not 10/02/94 JSP */
 
40
int bootp_debug   = 0 ;   /* debug mode or not 14/02/94 JSP */
 
41
 
 
42
static int returniffail ;  /* Return to the user if we fail */
 
43
static int printflag;      /* Print control */
 
44
static int sockfd;
 
45
 
 
46
int performBootp(char *device,
 
47
                 char *server,
 
48
                 char *bootfile,
 
49
                 int timeout_wait,
 
50
                 int givenhwaddr,
 
51
                 struct ifreq *their_ifr,
 
52
                 int waitformore,
 
53
                 int bp_rif,
 
54
                 int bp_pr,
 
55
                 int broadcast)
 
56
{
 
57
  struct ifreq ifr;
 
58
  struct sockaddr_in cli_addr, serv_addr;
 
59
  struct bootp *bootp_xmit, *bootp_recv;
 
60
  fd_set rfds, wfds, xfds;
 
61
  struct timeval timeout ;
 
62
  int32 rancopy ;
 
63
  int cookielength ;
 
64
  long plen ;
 
65
  int retry_wait, waited=0 ;
 
66
  int one=1, i ;
 
67
  struct timeval tp;
 
68
  int received_packet = 0 ;
 
69
/* See RFC1497, RFC1542  09/02/94   JSP  */
 
70
  unsigned char mincookie[] = {99,130,83,99,255} ;
 
71
 
 
72
  returniffail=bp_rif ;
 
73
  printflag=bp_pr ;
 
74
 
 
75
/* zero structure before use */
 
76
  memset((char *) &serv_addr, 0, sizeof(serv_addr));
 
77
 
 
78
  serv_addr.sin_family = AF_INET;
 
79
  serv_addr.sin_addr.s_addr = inet_addr(server) ;
 
80
  serv_addr.sin_port = htons(IPPORT_BOOTPS);
 
81
 
 
82
  if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
 
83
    perror("bootpc: socket failed");
 
84
    return BootpFatal();
 
85
  }
 
86
  
 
87
  if (setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&one,sizeof(one))==-1) {
 
88
    perror("bootpc: setsockopt failed");
 
89
    return BootpFatal();
 
90
  }
 
91
  
 
92
  memset((char *) &cli_addr, 0, sizeof(cli_addr));
 
93
  cli_addr.sin_family = AF_INET;
 
94
  cli_addr.sin_addr.s_addr = htonl(INADDR_ANY);
 
95
  cli_addr.sin_port = htons(IPPORT_BOOTPC);
 
96
 
 
97
  if(bind(sockfd, (struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0) {
 
98
    perror("bootpc: bind failed");
 
99
    return BootpFatal();
 
100
  }
 
101
 
 
102
/* allocate bootp packet before we use it */
 
103
  bootp_xmit = (struct bootp *) malloc(BUFSIZ) ;
 
104
  memset((char *) bootp_xmit, 0, BUFSIZ) ;
 
105
 
 
106
  bootp_recv = (struct bootp *) malloc(BUFSIZ) ;
 
107
  memset((char *) bootp_recv, 0, BUFSIZ) ;
 
108
 
 
109
  /* Server needs to broadcast for me to see it */
 
110
  if (broadcast || givenhwaddr)
 
111
    bootp_xmit->bp_flags |= htons(BPFLAG_BROADCAST);
 
112
 
 
113
/* Don't do this if we were given the MAC address to use.  27/09/94  JSP */
 
114
  if (givenhwaddr) {
 
115
    /* Assuming ETHER if given HW */
 
116
    ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER ;
 
117
    ifr.ifr_hwaddr = their_ifr->ifr_hwaddr ;
 
118
  } else {
 
119
/* Get the hardware address, and family information */
 
120
    memcpy(ifr.ifr_name, device, strlen(device)+1);
 
121
    if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) < 0) {
 
122
      perror("bootpc: ioctl failed");
 
123
      return BootpFatal();
 
124
    }
 
125
  }
 
126
 
 
127
/* Check the network family if in NET3 or later, before NET3 you couldn't
 
128
   examine this info (as far as I know.) */
 
129
 
 
130
/* set the htype field from the sa.family of the hardware address, if
 
131
   this doesn't work for your interface type let me know please. */
 
132
 
 
133
  bootp_xmit->bp_htype = ifr.ifr_hwaddr.sa_family;
 
134
  bootp_xmit->bp_hlen = IFHWADDRLEN ;  /* All MAC addresses are the same length */
 
135
  
 
136
  if (bootp_debug)
 
137
    logMessage("Got family=%d (Ether=%d)",
 
138
               bootp_xmit->bp_htype, ARPHRD_ETHER);
 
139
 
 
140
/* If we have the time seed with it xor the hardware address, otherwise
 
141
   use the hardware address 12/02/94 JSP */
 
142
  if (gettimeofday(&tp, NULL) == -1)
 
143
    rancopy = 0 ;
 
144
  else
 
145
    rancopy = tp.tv_sec + tp.tv_usec ;
 
146
 
 
147
/* Do the XOR */
 
148
  for (i=0; i < IFHWADDRLEN ; ++i) {
 
149
    ((unsigned char *)&rancopy)[ i % sizeof(rancopy) ] ^=
 
150
      ((unsigned char *)(ifr.use_hwaddr))[i] ;
 
151
  }
 
152
/* and set the seed */
 
153
  srand(rancopy) ;
 
154
 
 
155
  if(bootp_debug) {
 
156
    logMessage("hardware addr is :") ;
 
157
    for (i=0; i < bootp_xmit->bp_hlen ; ++i)
 
158
      logMessage("%2.2X ", ((unsigned char *)(ifr.use_hwaddr))[i]) ;
 
159
  }
 
160
 
 
161
/* Now fill in the packet. */
 
162
  bootp_xmit->bp_op = BOOTREQUEST ;
 
163
 
 
164
/* Now with my understanding of the bootp protocol we *should* just
 
165
   need to copy the hwaddr over, but it seems that at least ARCNET
 
166
   bootb servers are wird in this respect.  So here is a switch in
 
167
   case of other weirdness.  JSP */
 
168
 
 
169
  switch(bootp_xmit->bp_htype) {
 
170
/* ARCNET uses a "fake" ethernet address, with the ARCNET address at
 
171
   the wrong end.  At least the Novell bootp server on ARCNET assumes
 
172
   this.  Thanks to Tomasz Motylewski <motyl@tichy.ch.uj.edu.pl> for
 
173
   reporting this.  */
 
174
  case ARPHRD_ARCNET :
 
175
    memcpy(bootp_xmit->bp_chaddr+IFHWADDRLEN-1, (char *)(ifr.use_hwaddr), 1) ;
 
176
    bootp_xmit->bp_htype=ARPHRD_ETHER;
 
177
    bootp_xmit->bp_hlen=IFHWADDRLEN;
 
178
    break ;
 
179
 
 
180
/* Add other network weirdness here */
 
181
 
 
182
/* For sensible networks the rest is normal */
 
183
  default :
 
184
    memcpy(bootp_xmit->bp_chaddr,
 
185
           (char *)(ifr.use_hwaddr),
 
186
           bootp_xmit->bp_hlen) ;
 
187
  }
 
188
 
 
189
/* Must start with zero here, see RFC1542 09/02/94 JSP */
 
190
  bootp_xmit->bp_secs = 0;
 
191
 
 
192
/* Put in the minimal RFC1497 Magic cookie 09/02/94 JSP */
 
193
  memcpy(bootp_xmit->bp_vend, mincookie, sizeof(mincookie));
 
194
 
 
195
/* Put the user precified bootfile name in place 12/02/94 */
 
196
  memcpy(bootp_xmit->bp_file, bootfile, strlen(bootfile)+1);
 
197
 
 
198
/* put a random value in here, but keep a copy to check later 09/02/94  JSP */
 
199
  bootp_xmit->bp_xid = rancopy = rand() ;
 
200
 
 
201
  retry_wait = 2 ;
 
202
  if (bootp_verbose)
 
203
    logMessage("BOOTPclient broadcast...");
 
204
 
 
205
  while (((waited <= timeout_wait) && !received_packet) ||
 
206
         ((waited <= waitformore) && received_packet)) {
 
207
    
 
208
    if (!received_packet) {  /* Move this to a sendpacket function */
 
209
      /* set time of this timeout  09/02/94  JSP */
 
210
      bootp_xmit->bp_secs = waited ;
 
211
      if (bootp_verbose) {
 
212
        logMessage("."); fflush(stderr);
 
213
      }
 
214
      if (bootp_debug) {
 
215
        logMessage("Size = %ld", (long)sizeof(struct bootp)) ;
 
216
      }
 
217
 
 
218
      if(sendto(sockfd, bootp_xmit, sizeof(struct bootp), 0, 
 
219
                (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
 
220
        perror("bootpc: sendto");
 
221
        return BootpFatal();
 
222
      }
 
223
    }
 
224
 
 
225
    /* Move rest of this loop to a receivepacket function */
 
226
    FD_ZERO(&rfds);
 
227
/* The above was missing, thanks to
 
228
   Gilles Detillieux <grdetil@cliff.scrc.UManitoba.CA> for pointing it out */
 
229
    FD_SET(sockfd,&rfds);
 
230
    FD_ZERO(&wfds);
 
231
    FD_ZERO(&xfds);
 
232
 
 
233
/* Randomise the delays a little as suggested in RFC1542  09/02/94  JSP */
 
234
    timeout.tv_sec = retry_wait + (1+(rand() & (retry_wait-1))) ;
 
235
    timeout.tv_usec = 0;
 
236
    waited += timeout.tv_sec ;  /* Add this to the total time we have waited */
 
237
 
 
238
    if(select(sockfd+1, &rfds, &wfds, &xfds, &timeout)<0) {
 
239
      perror("bootpc: select");
 
240
      return BootpFatal();
 
241
    }
 
242
 
 
243
    if(!FD_ISSET(sockfd, &rfds)) {
 
244
      retry_wait = retry_wait*2;
 
245
    } else {
 
246
      if ((plen = recvfrom(sockfd, bootp_recv, BUFSIZ, 0,
 
247
                           (struct sockaddr *)NULL, (int *)NULL)) < 0){
 
248
        perror("bootpc: recvfrom");
 
249
        return BootpFatal();
 
250
      }
 
251
 
 
252
      if (bootp_debug) {
 
253
        logMessage("plen = %ld  plen - sizeof(struct bootp) = %ld",
 
254
                   (long)plen, (long)(plen - sizeof(struct bootp))) ;
 
255
      }
 
256
      cookielength = 64 + plen - sizeof(struct bootp) ;
 
257
      
 
258
      if (bootp_recv->bp_xid == rancopy) {  /* is xid right */
 
259
        if (!received_packet) {
 
260
          /* If we haven't already recieved a packet then set the time to wait
 
261
             further to be now + time user specified */
 
262
          waitformore += waited ;
 
263
          received_packet = 1 ;
 
264
        } else {
 
265
          /* To make it look a bit prettier */
 
266
          if (printflag & BP_PRINT_OUT)
 
267
            printf("\n") ;
 
268
        }
 
269
        /* Pass the cookie info, the mincookie to look for and our address to
 
270
           the cookie parser.  It needs our address to get the network and
 
271
           broadcast bits right if the SUBNET is defined in the cookie.
 
272
           10/02/94  JSP */
 
273
        ParsePacket(bootp_recv,
 
274
                    cookielength,
 
275
                    mincookie) ;
 
276
      } else {
 
277
        /* xid mismatch so normally silently ignore */
 
278
        if (bootp_verbose) {
 
279
          logMessage("WARNING bp_xid mismatch got 0x%lx sent 0x%lx",
 
280
                     (long)bootp_recv->bp_xid, (long)rancopy) ;
 
281
        }
 
282
      }
 
283
    }
 
284
  }
 
285
  if (!received_packet) {
 
286
    logMessage("No response from BOOTP server");
 
287
    return BootpFatal();
 
288
  }
 
289
 
 
290
  if (sockfd)
 
291
    close (sockfd) ;
 
292
  return 0 ;  /* Normal exit */
 
293
}
 
294
    
 
295
int BootpFatal()
 
296
{
 
297
  if (sockfd)
 
298
    close (sockfd) ;
 
299
 
 
300
  if (bootp_debug)
 
301
    logMessage("In BootpFatal(), errno was %d", errno) ;
 
302
 
 
303
  if (returniffail) {
 
304
    logMessage("bootpc failed to locate a network address") ;
 
305
    return 1 ;
 
306
  }
 
307
 
 
308
  logMessage(" Unable to locate an IP address for this host.\n"
 
309
             "     ***Please report this problem**\n\n"
 
310
             "          [Unable to continue]\n");
 
311
 
 
312
  if (bootp_debug)
 
313
    logMessage("Will now loop forerver, break out of this to fix") ;
 
314
 
 
315
  while(1) {
 
316
    /* your eyes are getting heavy.... */
 
317
    sleep(1000) ;
 
318
  }
 
319
}
 
320
 
 
321
/* Parse Magic cookies as specified in RFC1497, well only the bits we
 
322
   are actually interested in...  09/02/94 JSP
 
323
*/
 
324
void ParsePacket(struct bootp * bootp_recv,
 
325
                 int cookielength,
 
326
                 unsigned char *match)
 
327
{
 
328
  int i=0, len, tag ;
 
329
  int subnet = 0 ;
 
330
  struct in_addr temp ;
 
331
  unsigned char *cookie = (unsigned char *)(bootp_recv->bp_vend) ;
 
332
  struct in_addr temp_addr, my_addr ;
 
333
 
 
334
  temp_addr.s_addr = bootp_recv->bp_siaddr.s_addr ;
 
335
  OutString("SERVER", (unsigned char *)inet_ntoa(temp_addr), -1);
 
336
  my_addr.s_addr = bootp_recv->bp_yiaddr.s_addr ;
 
337
  OutString("IPADDR", (unsigned char *)inet_ntoa(my_addr), -1);
 
338
  if (bootp_verbose) {
 
339
    logMessage("bp_file len is %d", strlen(bootp_recv->bp_file)) ;
 
340
  }     
 
341
  OutString("BOOTFILE",
 
342
              (unsigned char *)bootp_recv->bp_file, -1) ;
 
343
 
 
344
  if (bootp_debug) {  /* dump cookie contents in HEX 10/02/94  JSP */
 
345
    for (i=0; i<cookielength; i++) {
 
346
      if ((i%8) == 0)
 
347
        logMessage("\n %2.2d :", i) ;
 
348
      logMessage(" 0x%2.2X", cookie[i]) ;
 
349
    }
 
350
    logMessage("") ;
 
351
  }
 
352
 
 
353
/* Must get the same cookie back as we sent  09/02/94  JSP */
 
354
  for (i=0; i < 4; ++i) {
 
355
    if (cookie[i] != match[i]) {
 
356
      if (bootp_verbose)
 
357
        logMessage("RFC1497 Cookie mismatch at offset %d", i) ;
 
358
      return ;
 
359
    }
 
360
  }
 
361
 
 
362
  if (bootp_verbose)
 
363
    logMessage("found valid RFC1497 cookie, parsing...") ;
 
364
 
 
365
/* Carry on after the cookie for other data  09/02/94  JSP */
 
366
  while (i < cookielength) {
 
367
    tag = cookie[i] ;
 
368
 
 
369
    if (bootp_verbose)
 
370
      logMessage("cookie position %d is %d", i, tag) ;
 
371
 
 
372
/* If we arn't at the end of the cookie and we will need it extract len */
 
373
    if ((i < cookielength - 1) && (tag != TAG_PAD) && (tag != TAG_END))
 
374
      len = cookie[i+1] ;
 
375
    else
 
376
      len = 0 ;
 
377
 
 
378
/* Warn if the "length" takes us out of the cookie and truncate */
 
379
    if (len + i > cookielength) {
 
380
      if (bootp_verbose)
 
381
        logMessage("TAG %d at %d.  len %d, overrun %d",
 
382
                   cookie[i], i, len, i + len - cookielength) ;
 
383
      /* And truncate in any case even with no warning */
 
384
      len = cookielength - i ;
 
385
    }
 
386
 
 
387
    switch (cookie[i]) {  /* The monster switch statement ... */
 
388
/* PAD cookie */
 
389
    case TAG_PAD :
 
390
      i++ ;
 
391
      break ;
 
392
 
 
393
/* SUBNET we are in */
 
394
    case TAG_SUBNET_MASK :
 
395
      if (bootp_verbose && len != 4)
 
396
        logMessage("WARNING len of tag 1 is %d not 4", len) ;
 
397
      memcpy((char *)&temp, cookie + i + 2, 4) ;
 
398
      OutString("NETMASK", (unsigned char *)inet_ntoa(temp), -1) ;
 
399
 
 
400
/* Both values are in network order so this doesn't care about the
 
401
   ordering 10/02/94 JSP */
 
402
      my_addr.s_addr &=  temp.s_addr ;
 
403
      OutString("NETWORK", (unsigned char *)inet_ntoa(my_addr), -1) ;
 
404
      my_addr.s_addr |= ~temp.s_addr ;
 
405
      OutString("BROADCAST", (unsigned char *)inet_ntoa(my_addr), -1) ;
 
406
 
 
407
/* defined so we know later that subnet info has been printed 11/02/94  JSP */
 
408
      subnet = 1 ;
 
409
      i += len + 2 ;
 
410
      break ;
 
411
 
 
412
/* Time of day */
 
413
    case TAG_TIME_OFFSET :
 
414
      /* ignored */
 
415
      i += len + 2 ;
 
416
      break ;
 
417
 
 
418
/* IP Gateways (routers) */
 
419
    case TAG_GATEWAY :
 
420
      OutList("GATEWAYS", cookie+i+2, len) ;
 
421
      i += len + 2 ;
 
422
      break ; 
 
423
 
 
424
/* Timeservers (see RFC-868) */
 
425
    case TAG_TIME_SERVER :
 
426
      OutList("TIMESRVS", cookie+i+2, len) ;
 
427
      i += len + 2 ;
 
428
      break ; 
 
429
 
 
430
/* IEN-116 Nameservers */
 
431
    case TAG_NAME_SERVER :
 
432
      OutList("IEN116SRVS", cookie+i+2, len) ;
 
433
      i += len + 2 ;
 
434
      break ; 
 
435
 
 
436
/* DNS Nameservers */
 
437
    case TAG_DOMAIN_SERVER :
 
438
      OutList("DNSSRVS", cookie+i+2, len) ;
 
439
      i += len + 2 ;
 
440
      break ; 
 
441
 
 
442
/* LOGGING servers */
 
443
    case TAG_LOG_SERVER :
 
444
      OutList("LOGSRVS", cookie+i+2, len) ;
 
445
      i += len + 2 ;
 
446
      break ; 
 
447
 
 
448
/* Quote of day/Cookie servers */
 
449
    case TAG_COOKIE_SERVER :
 
450
      OutList("QODSRVS", cookie+i+2, len) ;
 
451
      i += len + 2 ;
 
452
      break ; 
 
453
 
 
454
/* LPR servers */
 
455
    case TAG_LPR_SERVER :
 
456
      OutList("LPRSRVS", cookie+i+2, len) ;
 
457
      i += len + 2 ;
 
458
      break ; 
 
459
 
 
460
/* Impress (Imogen) servers */
 
461
    case TAG_IMPRESS_SERVER :
 
462
      OutList("IMPRESSSRVS", cookie+i+2, len) ;
 
463
      i += len + 2 ;
 
464
      break ; 
 
465
 
 
466
/* Remote Location Protocol servers */
 
467
    case TAG_RLP_SERVER :
 
468
      OutList("RLPSRVS", cookie+i+2, len) ;
 
469
      i += len + 2 ;
 
470
      break ; 
 
471
 
 
472
/* HOSTNAME (may be fqdn or leaf) */
 
473
    case TAG_HOST_NAME :
 
474
      OutString("HOSTNAME", cookie+i+2, len) ;
 
475
      i += len + 2 ;
 
476
      break ;
 
477
 
 
478
/* BOOT File Size (ignored) */
 
479
    case TAG_BOOT_SIZE :
 
480
      i += len + 2 ;
 
481
      break ;
 
482
 
 
483
/* Merit DUMP File name (ignored) */
 
484
    case TAG_DUMP_FILE :
 
485
      i += len + 2 ;
 
486
      break ;
 
487
 
 
488
/* DOMAIN */
 
489
    case TAG_DOMAIN_NAME :
 
490
      OutString("DOMAIN", cookie+i+2, len) ;
 
491
      OutSearch("SEARCH", cookie+i+2, len) ;
 
492
      i += len + 2 ;
 
493
      break ;
 
494
 
 
495
/* SWAPServer address */
 
496
    case TAG_SWAP_SERVER :
 
497
      OutList("SWAPSRVR", cookie+i+2, len) ;
 
498
      i += len + 2 ;
 
499
      break ;
 
500
 
 
501
/* Root pathname to mount as root filesystem  */
 
502
    case TAG_ROOT_PATH :
 
503
      OutString("ROOT_PATH", cookie+i+2, len) ;
 
504
      i += len + 2 ;
 
505
      break ;
 
506
 
 
507
/* Extensions.  Name of further Cookie data */
 
508
    case TAG_EXTEN_FILE :
 
509
      OutString("EXTEN_FILE", cookie+i+2, len) ;
 
510
      i += len + 2 ;
 
511
      break ;
 
512
 
 
513
/* NIS (formerly YP) domain name */
 
514
    case TAG_NIS_DOMAIN :
 
515
      OutString("YPDOMAIN", cookie+i+2, len) ;
 
516
      i += len + 2 ;
 
517
      break ;
 
518
       
 
519
/* NIS (formerly YP) server */
 
520
    case TAG_NIS_SERVER :
 
521
      OutList("YPSRVR", cookie+i+2, len) ;
 
522
      i += len + 2 ;
 
523
      break ;
 
524
       
 
525
/* Time servers */
 
526
    case TAG_NTP_SERVER :
 
527
      OutList("NTPSRVS", cookie+i+2, len) ;
 
528
      i += len + 2 ;
 
529
      break ;
 
530
 
 
531
/* END of cookie (phew) */
 
532
    case TAG_END :
 
533
      if (bootp_verbose)
 
534
        logMessage("end of cookie parsing, END tag found") ;
 
535
      return ;
 
536
 
 
537
    default:
 
538
      { char name[30] ;
 
539
        if (bootp_verbose) {
 
540
          if (tag >= 128 && tag <= 254) /* reserved */
 
541
            logMessage("Reserved TAG %d at %d (len %d)", tag, i, len) ;
 
542
          else
 
543
            logMessage("Unknown TAG %d at %d (len %d)", tag, i, len) ;
 
544
        }
 
545
        sprintf(name, "T%3.3d", tag) ;
 
546
        OutString(name, cookie+i+2, len) ;
 
547
        i += 2 + len ;
 
548
      }
 
549
      break ;
 
550
    }
 
551
  }
 
552
 
 
553
  /* No SUBNET TAG in the cookie so we fake guess here, if this is wrong
 
554
     then fix your bootp server to tell us the answer rather than
 
555
     hacking this code. */
 
556
 
 
557
  if (!subnet) {
 
558
    struct in_addr netmask ;
 
559
    int type ;
 
560
        
 
561
    if (bootp_verbose)
 
562
      logMessage("Guessing netmask from IP address range") ;
 
563
 
 
564
    type = ntohl(temp_addr.s_addr) ;
 
565
    if ((type & 0x80000000) == 0) {
 
566
      /* Class A */
 
567
      netmask.s_addr = htonl(0xFF000000) ;
 
568
    } else if ((type & 0x40000000) == 0) {
 
569
      /* Class B */
 
570
      netmask.s_addr = htonl(0xFFFF0000) ;
 
571
    } else if ((type & 0x20000000) == 0) {
 
572
      /* Class C */
 
573
      netmask.s_addr = htonl(0xFFFFFF00) ;
 
574
    } else { /* GOD KNOWS... other classes are weird */
 
575
      if (bootp_verbose)
 
576
        logMessage("IP number not Class A,B or C. Setting NETMASK to zero") ;
 
577
      netmask.s_addr = htonl(0x00000000) ;
 
578
    }
 
579
    OutString("NETMASK", (unsigned char *)inet_ntoa(netmask), -1);
 
580
    temp_addr.s_addr &= netmask.s_addr ;
 
581
    OutString("NETWORK", (unsigned char *)inet_ntoa(temp_addr), -1);
 
582
    temp_addr.s_addr |= ~netmask.s_addr ;
 
583
    OutString("BROADCAST", (unsigned char *)inet_ntoa(temp_addr), -1);
 
584
  }
 
585
}
 
586
 
 
587
 
 
588
/* Print out a list of IP addresses */
 
589
void OutList(char *name,
 
590
               unsigned char *cookie,
 
591
               int len)
 
592
{
 
593
  struct in_addr temp ;
 
594
  char lenv[BUFSIZ], *ptr ;
 
595
  int n, c, i;
 
596
 
 
597
  if (bootp_verbose)
 
598
    logMessage("%s found len=%d", name, len) ;
 
599
 
 
600
  if ((len % 4) != 0) {
 
601
    if (bootp_verbose)
 
602
      logMessage("ERROR %s length (%d) not 4 div", name, len) ;
 
603
    return ;
 
604
  }
 
605
  if (len == 0) /* Nothing to do  10/02/94  JSP */
 
606
    return ;
 
607
 
 
608
  for (n=0,i=1 ; len; len -= 4, cookie += 4, i++) {
 
609
    char lbuf[BUFSIZ] ;
 
610
    memcpy((char *)&temp, cookie, 4) ;
 
611
    ptr = inet_ntoa(temp) ;
 
612
    c = strlen(ptr) ;
 
613
    sprintf(lbuf, "%s_%d", name, i) ;
 
614
    OutString(lbuf, (unsigned char *)ptr, c) ;
 
615
    strncpy(lenv+n, ptr, c) ;
 
616
    n += c ;
 
617
    if (len > 4)
 
618
      lenv[n++] = ' ';
 
619
  }
 
620
  lenv[n] = 0 ;
 
621
 
 
622
  doOut(name, lenv) ;
 
623
}
 
624
 
 
625
/* Prints the string passed */
 
626
void OutString(char *name,
 
627
               unsigned char *cookie,
 
628
               int len)
 
629
{
 
630
  char lenv[BUFSIZ];
 
631
  if (len == -1)
 
632
    len = strlen((char *)cookie) ;
 
633
 
 
634
  safecopy((unsigned char *)lenv, cookie, len);
 
635
  doOut(name, lenv) ;
 
636
}
 
637
 
 
638
/* Prints the string as usable in a DNS search.  This is doing the
 
639
   same as the old default BIND (pre 4.9.3) did with a DOMAIN line,
 
640
   for backwards compatibility, and since BOOTP doesn't allow a way to
 
641
   specify the search path explicitly */
 
642
void OutSearch(char *name,
 
643
                 unsigned char *cookie,
 
644
                 int len)
 
645
{
 
646
  unsigned char *ptr, *nptr ;
 
647
  unsigned char buf[258] ;  /* Max len is 255 */
 
648
  char lenv[BUFSIZ] ;
 
649
  int n=0;
 
650
 
 
651
  strncpy((char *)buf, (char *)(cookie), len) ;
 
652
  buf[ len + 1 ] = 0 ;  /* Null terminate it */
 
653
  ptr = buf ;
 
654
 
 
655
  while (len) {
 
656
    safecopy((unsigned char *)(lenv+n), ptr, len) ;
 
657
    n += len ;
 
658
    /* Goto next bit */
 
659
    nptr = (unsigned char *)strchr((char *)ptr, '.') ;  /* Cast cast cast */
 
660
    if (nptr == NULL) {
 
661
      len = 0 ; /* End of string I hope */
 
662
    } else {
 
663
      if (strchr((char *)nptr + 1, '.') == NULL) {
 
664
        /* Trad to not use last component */
 
665
        len = 0 ;
 
666
      } else {
 
667
        len -= (nptr - ptr) + 1 ;
 
668
        ptr = nptr + 1 ;
 
669
        lenv[n++] = ' ' ;
 
670
      }
 
671
    }
 
672
  }
 
673
  lenv[n] = 0 ;
 
674
 
 
675
  doOut(name, lenv) ;
 
676
}
 
677
 
 
678
/* Takes an address and returns useful bits of the name after lookup,
 
679
   this was a seperate program, but it is more compact to have both
 
680
   together.  17/02/94  JSP */
 
681
 
 
682
int in2host(char *address,
 
683
            int bp_pr)
 
684
{
 
685
  struct in_addr sin_addr;
 
686
  struct hostent *hp;
 
687
  char *c ;
 
688
 
 
689
  printflag=bp_pr ;
 
690
 
 
691
/* convert to standard network form */
 
692
  sin_addr.s_addr = inet_addr(address);
 
693
 
 
694
/* perform lookup, must have DNS running or have local hosts file at
 
695
   this point */
 
696
 
 
697
  hp = gethostbyaddr((char *)&sin_addr, sizeof(sin_addr), AF_INET) ;
 
698
 
 
699
  if (hp == NULL) {
 
700
    perror ("bootpc: gethostbyaddr") ;
 
701
    return -1;
 
702
  }
 
703
 
 
704
/* Print out a known name to stop repeated calls */
 
705
  OutString("DONEIN2HOST",(unsigned char *)"1", -1) ;
 
706
 
 
707
/* Print out full name as returned by the call */
 
708
  OutString("HOSTFULL", (unsigned char *)(hp->h_name), -1) ;
 
709
 
 
710
  for(c=(char *)hp->h_name; *c ; ++c)
 
711
    if(*c == '.') {
 
712
/* Zap first 'dot' to give leaf and domain names */
 
713
      OutString("HOSTDOMAIN", (unsigned char *)(c+1), -1) ;
 
714
      OutSearch("HOSTSEARCH", (unsigned char *)(c+1), strlen(c+1)) ;
 
715
      *c = 0 ;
 
716
      OutString("HOSTLEAF", (unsigned char *)(hp->h_name), -1) ;
 
717
      return 0 ;
 
718
    }
 
719
  return 0 ;
 
720
}
 
721
 
 
722
/* Copy those bits of a string which are alphanumeric or in a
 
723
   "safe" list of characters. */
 
724
void safecopy(unsigned char *out,
 
725
              unsigned char *string,
 
726
              int len)
 
727
{
 
728
  char safe[] = "./:-_=+[]~()%&*^#@! " ;
 
729
  int i, c ;
 
730
 
 
731
  for (i =0 ; i < len; ++i) {
 
732
    c = string[i] ;
 
733
    if (isalnum(c))
 
734
      out[i] = c ;   /* alphanumeric */
 
735
    else {  /* Not alphanumeric */
 
736
      if (strchr(safe, c) != NULL) {
 
737
        out[i] = c ; /* but safe */
 
738
      } else {
 
739
        out[i] = '?' ; /* NOT safe */
 
740
        if (bootp_verbose)
 
741
          logMessage("Illegal char 0x%2.2X", c) ;
 
742
      }
 
743
    }
 
744
  }
 
745
  out[i] = 0 ;
 
746
}
 
747
 
 
748
void doOut(char *name,
 
749
           char *lenv)
 
750
{
 
751
  if (printflag & BP_PRINT_OUT) {
 
752
    printf("%s='%s'\n", name, lenv) ;
 
753
  }
 
754
  if (printflag & BP_PUT_ENV) {
 
755
    char envb[BUFSIZ], *envp ;
 
756
    sprintf(envb, "BOOTP_%s=%s", name, lenv) ;
 
757
    envp = strdup(envb) ;
 
758
    if (bootp_debug)
 
759
      logMessage("ENV setting :%s:", envp) ;
 
760
    putenv(envp) ;
 
761
  }
 
762
}