~ubuntu-branches/ubuntu/natty/curl/natty-security

« back to all changes in this revision

Viewing changes to lib/hostip.c

  • Committer: Bazaar Package Importer
  • Author(s): Bhavani Shankar
  • Date: 2010-06-20 13:56:28 UTC
  • mfrom: (3.4.7 sid)
  • Revision ID: james.westby@ubuntu.com-20100620135628-e30tp9jldq6hq985
Tags: 7.21.0-1ubuntu1
* Merge from debian unstable.  Remaining changes: LP: #596334
  - Keep build deps in main:
    - Drop build dependencies: stunnel, libssh2-1-dev
    - Add build-dependency on openssh-server
    - Drop libssh2-1-dev from libcurl4-openssl-dev's Depends.

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
 *                            | (__| |_| |  _ <| |___
6
6
 *                             \___|\___/|_| \_\_____|
7
7
 *
8
 
 * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
 
8
 * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
9
9
 *
10
10
 * This software is licensed as described in the file COPYING, which
11
11
 * you should have received as part of this distribution. The terms
18
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
19
 * KIND, either express or implied.
20
20
 *
21
 
 * $Id: hostip.c,v 1.217 2009-09-01 14:27:01 bagder Exp $
22
21
 ***************************************************************************/
23
22
 
24
23
#include "setup.h"
43
42
#ifdef HAVE_UNISTD_H
44
43
#include <unistd.h>     /* for the close() proto */
45
44
#endif
46
 
#ifdef  VMS
 
45
#ifdef __VMS
47
46
#include <in.h>
48
47
#include <inet.h>
49
48
#include <stdlib.h>
76
75
/* The last #include file should be: */
77
76
#include "memdebug.h"
78
77
 
79
 
#if defined(HAVE_ALARM) && defined(SIGALRM) && defined(HAVE_SIGSETJMP) \
80
 
    && !defined(USE_ARES)
 
78
#if defined(CURLRES_SYNCH) && \
 
79
    defined(HAVE_ALARM) && defined(SIGALRM) && defined(HAVE_SIGSETJMP)
81
80
/* alarm-based timeouts can only be used with all the dependencies satisfied */
82
81
#define USE_ALARM_TIMEOUT
83
82
#endif
189
188
    case AF_INET:
190
189
      sa4 = (const void *)ai->ai_addr;
191
190
      ipaddr4 = &sa4->sin_addr;
192
 
      return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf, bufsize);
 
191
      return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf,
 
192
                            bufsize);
193
193
#ifdef ENABLE_IPV6
194
194
    case AF_INET6:
195
195
      sa6 = (const void *)ai->ai_addr;
196
196
      ipaddr6 = &sa6->sin6_addr;
197
 
      return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf, bufsize);
 
197
      return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf,
 
198
                            bufsize);
198
199
#endif
199
200
    default:
200
201
      break;
232
233
    (struct hostcache_prune_data *) datap;
233
234
  struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
234
235
 
235
 
  if((data->now - c->timestamp < data->cache_timeout) ||
236
 
      c->inuse) {
237
 
    /* please don't remove */
238
 
    return 0;
239
 
  }
240
 
 
241
 
  /* fine, remove */
242
 
  return 1;
 
236
  return (data->now - c->timestamp >= data->cache_timeout);
243
237
}
244
238
 
245
239
/*
339
333
  size_t entry_len;
340
334
  struct Curl_dns_entry *dns;
341
335
  struct Curl_dns_entry *dns2;
342
 
  time_t now;
343
336
 
344
337
  /* Create an entry id, based upon the hostname and port */
345
338
  entry_id = create_hostcache_id(hostname, port);
349
342
  entry_len = strlen(entry_id);
350
343
 
351
344
  /* Create a new cache entry */
352
 
  dns = calloc(sizeof(struct Curl_dns_entry), 1);
 
345
  dns = calloc(1, sizeof(struct Curl_dns_entry));
353
346
  if(!dns) {
354
347
    free(entry_id);
355
348
    return NULL;
357
350
 
358
351
  dns->inuse = 0;   /* init to not used */
359
352
  dns->addr = addr; /* this is the address(es) */
 
353
  time(&dns->timestamp);
 
354
  if(dns->timestamp == 0)
 
355
    dns->timestamp = 1;   /* zero indicates that entry isn't in hash table */
360
356
 
361
 
  /* Store the resolved data in our DNS cache. This function may return a
362
 
     pointer to an existing struct already present in the hash, and it may
363
 
     return the same argument we pass in. Make no assumptions. */
 
357
  /* Store the resolved data in our DNS cache. */
364
358
  dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len+1,
365
359
                       (void *)dns);
366
360
  if(!dns2) {
367
 
    /* Major badness, run away. */
368
361
    free(dns);
369
362
    free(entry_id);
370
363
    return NULL;
371
364
  }
372
 
  time(&now);
 
365
 
373
366
  dns = dns2;
374
 
 
375
 
  dns->timestamp = now; /* used now */
376
367
  dns->inuse++;         /* mark entry as in-use */
377
368
 
378
369
  /* free the allocated entry_id again */
551
542
#ifdef USE_ALARM_TIMEOUT
552
543
#ifdef HAVE_SIGACTION
553
544
  struct sigaction keep_sigact;   /* store the old struct here */
554
 
  bool keep_copysig=FALSE;        /* did copy it? */
 
545
  volatile bool keep_copysig = FALSE; /* wether old sigact has been saved */
555
546
  struct sigaction sigact;
556
547
#else
557
548
#ifdef HAVE_SIGNAL
559
550
#endif /* HAVE_SIGNAL */
560
551
#endif /* HAVE_SIGACTION */
561
552
  volatile long timeout;
562
 
  unsigned int prev_alarm=0;
 
553
  volatile unsigned int prev_alarm = 0;
563
554
  struct SessionHandle *data = conn->data;
564
555
#endif /* USE_ALARM_TIMEOUT */
565
556
  int rc;
573
564
  else
574
565
    timeout = timeoutms;
575
566
 
576
 
  if(timeout && timeout < 1000)
 
567
  if(!timeout)
 
568
    /* USE_ALARM_TIMEOUT defined, but no timeout actually requested */
 
569
    return Curl_resolv(conn, hostname, port, entry);
 
570
 
 
571
  if(timeout < 1000)
577
572
    /* The alarm() function only provides integer second resolution, so if
578
573
       we want to wait less than one second we must bail out already now. */
579
574
    return CURLRESOLV_TIMEDOUT;
580
575
 
581
 
  if (timeout > 0) {
582
 
    /* This allows us to time-out from the name resolver, as the timeout
583
 
       will generate a signal and we will siglongjmp() from that here.
584
 
       This technique has problems (see alarmfunc). */
585
 
      if(sigsetjmp(curl_jmpenv, 1)) {
586
 
        /* this is coming from a siglongjmp() after an alarm signal */
587
 
        failf(data, "name lookup timed out");
588
 
        return CURLRESOLV_ERROR;
589
 
      }
590
 
 
591
 
    /*************************************************************
592
 
     * Set signal handler to catch SIGALRM
593
 
     * Store the old value to be able to set it back later!
594
 
     *************************************************************/
 
576
  /*************************************************************
 
577
   * Set signal handler to catch SIGALRM
 
578
   * Store the old value to be able to set it back later!
 
579
   *************************************************************/
595
580
#ifdef HAVE_SIGACTION
596
 
    sigaction(SIGALRM, NULL, &sigact);
597
 
    keep_sigact = sigact;
598
 
    keep_copysig = TRUE; /* yes, we have a copy */
599
 
    sigact.sa_handler = alarmfunc;
 
581
  sigaction(SIGALRM, NULL, &sigact);
 
582
  keep_sigact = sigact;
 
583
  keep_copysig = TRUE; /* yes, we have a copy */
 
584
  sigact.sa_handler = alarmfunc;
600
585
#ifdef SA_RESTART
601
 
    /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */
602
 
    sigact.sa_flags &= ~SA_RESTART;
 
586
  /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */
 
587
  sigact.sa_flags &= ~SA_RESTART;
603
588
#endif
604
 
    /* now set the new struct */
605
 
    sigaction(SIGALRM, &sigact, NULL);
 
589
  /* now set the new struct */
 
590
  sigaction(SIGALRM, &sigact, NULL);
606
591
#else /* HAVE_SIGACTION */
607
 
    /* no sigaction(), revert to the much lamer signal() */
 
592
  /* no sigaction(), revert to the much lamer signal() */
608
593
#ifdef HAVE_SIGNAL
609
 
    keep_sigact = signal(SIGALRM, alarmfunc);
 
594
  keep_sigact = signal(SIGALRM, alarmfunc);
610
595
#endif
611
596
#endif /* HAVE_SIGACTION */
612
597
 
613
 
    /* alarm() makes a signal get sent when the timeout fires off, and that
614
 
       will abort system calls */
615
 
    prev_alarm = alarm((unsigned int) (timeout/1000L));
 
598
  /* alarm() makes a signal get sent when the timeout fires off, and that
 
599
     will abort system calls */
 
600
  prev_alarm = alarm((unsigned int) (timeout/1000L));
 
601
 
 
602
  /* This allows us to time-out from the name resolver, as the timeout
 
603
     will generate a signal and we will siglongjmp() from that here.
 
604
     This technique has problems (see alarmfunc).
 
605
     This should be the last thing we do before calling Curl_resolv(),
 
606
     as otherwise we'd have to worry about variables that get modified
 
607
     before we invoke Curl_resolv() (and thus use "volatile"). */
 
608
  if(sigsetjmp(curl_jmpenv, 1)) {
 
609
    /* this is coming from a siglongjmp() after an alarm signal */
 
610
    failf(data, "name lookup timed out");
 
611
    rc = CURLRESOLV_ERROR;
 
612
    goto clean_up;
616
613
  }
617
614
 
618
615
#else
630
627
  rc = Curl_resolv(conn, hostname, port, entry);
631
628
 
632
629
#ifdef USE_ALARM_TIMEOUT
633
 
  if (timeout > 0) {
 
630
clean_up:
 
631
 
 
632
  if(!prev_alarm)
 
633
    /* deactivate a possibly active alarm before uninstalling the handler */
 
634
    alarm(0);
634
635
 
635
636
#ifdef HAVE_SIGACTION
636
 
    if(keep_copysig) {
637
 
      /* we got a struct as it looked before, now put that one back nice
638
 
         and clean */
639
 
      sigaction(SIGALRM, &keep_sigact, NULL); /* put it back */
640
 
    }
 
637
  if(keep_copysig) {
 
638
    /* we got a struct as it looked before, now put that one back nice
 
639
       and clean */
 
640
    sigaction(SIGALRM, &keep_sigact, NULL); /* put it back */
 
641
  }
641
642
#else
642
643
#ifdef HAVE_SIGNAL
643
 
    /* restore the previous SIGALRM handler */
644
 
    signal(SIGALRM, keep_sigact);
 
644
  /* restore the previous SIGALRM handler */
 
645
  signal(SIGALRM, keep_sigact);
645
646
#endif
646
647
#endif /* HAVE_SIGACTION */
647
648
 
648
 
    /* switch back the alarm() to either zero or to what it was before minus
649
 
       the time we spent until now! */
650
 
    if(prev_alarm) {
651
 
      /* there was an alarm() set before us, now put it back */
652
 
      unsigned long elapsed_ms = Curl_tvdiff(Curl_tvnow(), conn->created);
653
 
 
654
 
      /* the alarm period is counted in even number of seconds */
655
 
      unsigned long alarm_set = prev_alarm - elapsed_ms/1000;
656
 
 
657
 
      if(!alarm_set ||
658
 
         ((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) {
659
 
        /* if the alarm time-left reached zero or turned "negative" (counted
660
 
           with unsigned values), we should fire off a SIGALRM here, but we
661
 
           won't, and zero would be to switch it off so we never set it to
662
 
           less than 1! */
663
 
        alarm(1);
664
 
        rc = CURLRESOLV_TIMEDOUT;
665
 
        failf(data, "Previous alarm fired off!");
666
 
      }
667
 
      else
668
 
        alarm((unsigned int)alarm_set);
 
649
  /* switch back the alarm() to either zero or to what it was before minus
 
650
     the time we spent until now! */
 
651
  if(prev_alarm) {
 
652
    /* there was an alarm() set before us, now put it back */
 
653
    unsigned long elapsed_ms = Curl_tvdiff(Curl_tvnow(), conn->created);
 
654
 
 
655
    /* the alarm period is counted in even number of seconds */
 
656
    unsigned long alarm_set = prev_alarm - elapsed_ms/1000;
 
657
 
 
658
    if(!alarm_set ||
 
659
       ((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) {
 
660
      /* if the alarm time-left reached zero or turned "negative" (counted
 
661
         with unsigned values), we should fire off a SIGALRM here, but we
 
662
         won't, and zero would be to switch it off so we never set it to
 
663
         less than 1! */
 
664
      alarm(1);
 
665
      rc = CURLRESOLV_TIMEDOUT;
 
666
      failf(data, "Previous alarm fired off!");
669
667
    }
670
668
    else
671
 
      alarm(0); /* just shut it off */
 
669
      alarm((unsigned int)alarm_set);
672
670
  }
673
671
#endif /* USE_ALARM_TIMEOUT */
674
672
 
688
686
    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
689
687
 
690
688
  dns->inuse--;
 
689
  /* only free if nobody is using AND it is not in hostcache (timestamp ==
 
690
     0) */
 
691
  if (dns->inuse == 0 && dns->timestamp == 0) {
 
692
    Curl_freeaddrinfo(dns->addr);
 
693
    free(dns);
 
694
  }
691
695
 
692
696
  if(data->share)
693
697
    Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
700
704
{
701
705
  struct Curl_dns_entry *p = (struct Curl_dns_entry *) freethis;
702
706
 
703
 
  if(p) {
 
707
  /* mark the entry as not in hostcache */
 
708
  p->timestamp = 0;
 
709
  if (p->inuse == 0) {
704
710
    Curl_freeaddrinfo(p->addr);
705
711
    free(p);
706
712
  }
714
720
  return Curl_hash_alloc(7, Curl_hash_str, Curl_str_key_compare, freednsentry);
715
721
}
716
722
 
717
 
#ifdef CURLRES_ADDRINFO_COPY
718
 
 
719
 
/* align on even 64bit boundaries */
720
 
#define MEMALIGN(x) ((x)+(8-(((unsigned long)(x))&0x7)))
721
 
 
722
 
/*
723
 
 * Curl_addrinfo_copy() performs a "deep" copy of a hostent into a buffer and
724
 
 * returns a pointer to the malloc()ed copy. You need to call free() on the
725
 
 * returned buffer when you're done with it.
726
 
 */
727
 
Curl_addrinfo *Curl_addrinfo_copy(const void *org, int port)
728
 
{
729
 
  const struct hostent *orig = org;
730
 
 
731
 
  return Curl_he2ai(orig, port);
732
 
}
733
 
#endif /* CURLRES_ADDRINFO_COPY */
 
723