~ubuntu-branches/debian/sid/mtr/sid

« back to all changes in this revision

Viewing changes to net.c

  • Committer: Bazaar Package Importer
  • Author(s): Robert Woodcock
  • Date: 2008-09-22 07:30:21 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20080922073021-worxo2arrx3glvtn
Tags: 0.75-2
Use rm -f in rules clean target where necessary, closes: #499789

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
#include <netinet/in.h>
33
33
#include <memory.h>
34
34
#include <unistd.h>
 
35
#ifdef HAVE_FCNTL_H
 
36
#include <fcntl.h>
 
37
#endif
35
38
#include <stdio.h>
36
39
#include <stdlib.h>
37
40
#include <math.h>
54
57
  uint16 sequence;
55
58
};
56
59
 
 
60
/* Structure of an UDP header.  */
 
61
struct UDPHeader {
 
62
  uint16 srcport;
 
63
  uint16 dstport;
 
64
  uint16 length;
 
65
  uint16 checksum;
 
66
};
 
67
 
 
68
/* Structure of an IPv4 UDP pseudoheader.  */
 
69
struct UDPv4PHeader {
 
70
  uint32 saddr;
 
71
  uint32 daddr;
 
72
  uint8 zero;
 
73
  uint8 protocol;
 
74
  uint16 len;
 
75
};
57
76
 
58
77
/*  Structure of an IP header.  */
59
78
struct IPHeader {
77
96
#define ICMP_TSTAMPREPLY        14
78
97
 
79
98
#define ICMP_TIME_EXCEEDED      11
 
99
#define ICMP_UNREACHABLE        3
80
100
 
81
101
#ifndef SOL_IP
82
102
#define SOL_IP 0
131
151
 
132
152
int    timestamp;
133
153
int    sendsock4;
 
154
int    sendsock4_icmp;
 
155
int    sendsock4_udp;
134
156
int    recvsock4;
135
157
int    sendsock6;
 
158
int    sendsock6_icmp;
 
159
int    sendsock6_udp;
136
160
int    recvsock6;
137
161
int    sendsock;
138
162
int    recvsock;
175
199
extern int bitpattern;          /* packet bit pattern used by ping */
176
200
extern int tos;                 /* type of service set in ping packet*/
177
201
extern int af;                  /* address family of remote target */
178
 
 
 
202
extern int mtrtype;             /* type of query packet used */
179
203
 
180
204
/* return the number of microseconds to wait before sending the next
181
205
   ping */
206
230
}
207
231
 
208
232
 
 
233
/* Prepend pseudoheader to the udp datagram and calculate checksum */
 
234
int udp_checksum(void *pheader, void *udata, int psize, int dsize)
 
235
{
 
236
  unsigned int tsize = psize + dsize;
 
237
  char csumpacket[tsize];
 
238
  memset(csumpacket, (unsigned char) abs(bitpattern), abs(tsize));
 
239
 
 
240
  struct UDPv4PHeader *prepend = (struct UDPv4PHeader *) csumpacket;
 
241
  struct UDPv4PHeader *udppheader = (struct UDPv4PHeader *) pheader;
 
242
  prepend->saddr = udppheader->saddr;
 
243
  prepend->daddr = udppheader->daddr;
 
244
  prepend->zero = 0;
 
245
  prepend->protocol = udppheader->protocol;
 
246
  prepend->len = udppheader->len;
 
247
 
 
248
  struct UDPHeader *content = (struct UDPHeader *)(csumpacket + psize);
 
249
  struct UDPHeader *udpdata = (struct UDPHeader *) udata;
 
250
  content->srcport = udpdata->srcport;
 
251
  content->dstport = udpdata->dstport;
 
252
  content->length = udpdata->length;
 
253
  content->checksum = udpdata->checksum;
 
254
 
 
255
  return checksum(csumpacket,tsize);
 
256
}
 
257
 
 
258
 
209
259
int new_sequence(int index) 
210
260
{
211
 
  static int next_sequence = 0;
 
261
  static int next_sequence = MinSequence;
212
262
  int seq;
213
263
 
214
264
  seq = next_sequence++;
215
265
  if (next_sequence >= MaxSequence)
216
 
    next_sequence = 0;
 
266
    next_sequence = MinSequence;
217
267
 
218
268
  sequence[seq].index = index;
219
269
  sequence[seq].transit = 1;
236
286
  /*ok  char packet[sizeof(struct IPHeader) + sizeof(struct ICMPHeader)];*/
237
287
  char packet[MAXPACKET];
238
288
  struct IPHeader *ip = (struct IPHeader *) packet;
239
 
  struct ICMPHeader *icmp;
 
289
  struct ICMPHeader *icmp = NULL;
 
290
  struct UDPHeader *udp = NULL;
 
291
  struct UDPv4PHeader *udpp = NULL;
 
292
  uint16 mypid;
240
293
 
241
294
  /*ok  int packetsize = sizeof(struct IPHeader) + sizeof(struct ICMPHeader) + datasize;*/
242
295
  int rv;
243
296
  static int first=1;
244
 
  int ttl, iphsize = 0, echotype = 0, salen = 0;
 
297
  int ttl, iphsize = 0, echotype = 0, salen = 0, udphsize = 0;
245
298
 
246
299
  ttl = index + 1;
247
300
 
 
301
  /* offset for ipv6 checksum calculation */
 
302
  int offset = 6;
 
303
 
248
304
  if ( packetsize < MINPACKET ) packetsize = MINPACKET;
249
305
  if ( packetsize > MAXPACKET ) packetsize = MAXPACKET;
250
306
 
271
327
  ip->id = 0;
272
328
  ip->frag = 0;    /* 1, if want to find mtu size? Min */
273
329
    ip->ttl = ttl;
274
 
  ip->protocol = IPPROTO_ICMP;
 
330
  ip->protocol = mtrtype;
275
331
  ip->check = 0;
276
332
 
277
333
  /* BSD needs the source address here, Linux & others do not... */
295
351
#endif
296
352
  }
297
353
 
298
 
  icmp = (struct ICMPHeader *)(packet + iphsize);
299
 
  icmp->type     = echotype;
300
 
  icmp->code     = 0;
301
 
  icmp->checksum = 0;
302
 
  icmp->id       = getpid();
303
 
  icmp->sequence = new_sequence(index);
304
 
  icmp->checksum = checksum(icmp, abs(packetsize) - iphsize);
 
354
  switch ( mtrtype ) {
 
355
  case IPPROTO_ICMP:
 
356
    icmp = (struct ICMPHeader *)(packet + iphsize);
 
357
    icmp->type     = echotype;
 
358
    icmp->code     = 0;
 
359
    icmp->checksum = 0;
 
360
    icmp->id       = getpid();
 
361
    icmp->sequence = new_sequence(index);
 
362
    icmp->checksum = checksum(icmp, abs(packetsize) - iphsize);
 
363
    
 
364
    gettimeofday(&sequence[icmp->sequence].time, NULL);
 
365
    break;
 
366
 
 
367
  case IPPROTO_UDP:
 
368
    udp = (struct UDPHeader *)(packet + iphsize);
 
369
    udphsize = sizeof (struct UDPHeader);
 
370
    udp->checksum  = 0;
 
371
    mypid = (uint16)getpid();
 
372
    if (mypid < MinPort)
 
373
      mypid += MinPort;
 
374
 
 
375
    udp->srcport = htons(mypid);
 
376
    udp->length = abs(packetsize) - iphsize;
 
377
    if(!BSDfix)
 
378
      udp->length = htons(udp->length);
 
379
 
 
380
    udp->dstport = new_sequence(index);
 
381
    gettimeofday(&sequence[udp->dstport].time, NULL);
 
382
    udp->dstport = htons(udp->dstport);
 
383
    break;
 
384
  }
305
385
 
306
386
  switch ( af ) {
307
387
  case AF_INET:
 
388
    switch ( mtrtype ) {
 
389
    case IPPROTO_UDP:
 
390
      /* checksum is not mandatory. only calculate if we know ip->saddr */
 
391
      if (ip->saddr) {
 
392
        udpp = (struct UDPv4PHeader *)(malloc(sizeof(struct UDPv4PHeader)));
 
393
        udpp->saddr = ip->saddr;
 
394
        udpp->daddr = ip->daddr;
 
395
        udpp->protocol = ip->protocol;
 
396
        udpp->len = udp->length;
 
397
        udp->checksum = udp_checksum(udpp, udp, sizeof(struct UDPv4PHeader), abs(packetsize) - iphsize);
 
398
      }
 
399
      break;
 
400
    }
 
401
 
308
402
    ip->check = checksum(packet, abs(packetsize));
309
403
    break;
 
404
#ifdef ENABLE_IPV6
 
405
  case AF_INET6:
 
406
    switch ( mtrtype ) {
 
407
    case IPPROTO_UDP:
 
408
      /* kernel checksum calculation */
 
409
      if ( setsockopt(sendsock, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, sizeof(offset)) ) {
 
410
        perror( "setsockopt IPV6_CHECKSUM" );
 
411
        exit( EXIT_FAILURE);
 
412
      }
 
413
      break;
 
414
    }
 
415
    break;
 
416
#endif
310
417
  }
311
418
 
312
 
  gettimeofday(&sequence[icmp->sequence].time, NULL);
313
 
 
314
419
  rv = sendto(sendsock, packet, abs(packetsize), 0, 
315
420
              remotesockaddr, salen);
316
421
  if (first && (rv < 0) && ((errno == EINVAL) || (errno == EMSGSIZE))) {
450
555
  socklen_t fromsockaddrsize;
451
556
  int num;
452
557
  struct ICMPHeader *header = NULL;
 
558
  struct UDPHeader *udpheader = NULL;
453
559
  struct timeval now;
454
560
  ip_t * fromaddress = NULL;
455
 
  int echoreplytype = 0, timeexceededtype = 0;
 
561
  int echoreplytype = 0, timeexceededtype = 0, unreachabletype = 0;
 
562
  int sequence = 0;
456
563
 
457
564
  gettimeofday(&now, NULL);
458
565
  switch ( af ) {
461
568
    fromaddress = (ip_t *) &(fsa4->sin_addr);
462
569
    echoreplytype = ICMP_ECHOREPLY;
463
570
    timeexceededtype = ICMP_TIME_EXCEEDED;
 
571
    unreachabletype = ICMP_UNREACHABLE;
464
572
    break;
465
573
#ifdef ENABLE_IPV6
466
574
  case AF_INET6:
468
576
    fromaddress = (ip_t *) &(fsa6->sin6_addr);
469
577
    echoreplytype = ICMP6_ECHO_REPLY;
470
578
    timeexceededtype = ICMP6_TIME_EXCEEDED;
 
579
    unreachabletype = ICMP6_DST_UNREACH;
471
580
    break;
472
581
#endif
473
582
  }
490
599
    break;
491
600
#endif
492
601
  }
493
 
  if (header->type == echoreplytype) {
494
 
    if(header->id != (uint16)getpid())
495
 
      return;
496
 
 
497
 
    net_process_ping (header->sequence, (void *) fromaddress, now);
498
 
  } else if (header->type == timeexceededtype) {
499
 
    switch ( af ) {
500
 
    case AF_INET:
501
 
 
502
 
      if ((size_t) num < sizeof(struct IPHeader) + 
503
 
                         sizeof(struct ICMPHeader) + 
504
 
                         sizeof (struct IPHeader) + 
505
 
                         sizeof (struct ICMPHeader))
506
 
        return;
507
 
      header = (struct ICMPHeader *)(packet + sizeof (struct IPHeader) + 
508
 
                                              sizeof (struct ICMPHeader) + 
509
 
                                              sizeof (struct IPHeader));
510
 
    break;
511
 
#ifdef ENABLE_IPV6
512
 
    case AF_INET6:
513
 
      if ( num < sizeof (struct ICMPHeader) + 
514
 
                 sizeof (struct ip6_hdr) + sizeof (struct ICMPHeader) )
515
 
        return;
516
 
      header = (struct ICMPHeader *) ( packet + 
517
 
                                       sizeof (struct ICMPHeader) +
518
 
                                       sizeof (struct ip6_hdr) );
519
 
      break;
520
 
#endif
521
 
    }
522
 
 
523
 
    if (header->id != (uint16)getpid())
524
 
      return;
525
 
 
526
 
    net_process_ping(header->sequence, (void *)fromaddress, now);
 
602
 
 
603
  switch ( mtrtype ) {
 
604
  case IPPROTO_ICMP:
 
605
    if (header->type == echoreplytype) {
 
606
      if(header->id != (uint16)getpid())
 
607
        return;
 
608
 
 
609
      sequence = header->sequence;
 
610
    } else if (header->type == timeexceededtype) {
 
611
      switch ( af ) {
 
612
      case AF_INET:
 
613
 
 
614
        if ((size_t) num < sizeof(struct IPHeader) + 
 
615
                           sizeof(struct ICMPHeader) + 
 
616
                           sizeof (struct IPHeader) + 
 
617
                           sizeof (struct ICMPHeader))
 
618
          return;
 
619
        header = (struct ICMPHeader *)(packet + sizeof (struct IPHeader) + 
 
620
                                                sizeof (struct ICMPHeader) + 
 
621
                                                sizeof (struct IPHeader));
 
622
      break;
 
623
#ifdef ENABLE_IPV6
 
624
      case AF_INET6:
 
625
        if ( num < sizeof (struct ICMPHeader) + 
 
626
                   sizeof (struct ip6_hdr) + sizeof (struct ICMPHeader) )
 
627
          return;
 
628
        header = (struct ICMPHeader *) ( packet + 
 
629
                                         sizeof (struct ICMPHeader) +
 
630
                                         sizeof (struct ip6_hdr) );
 
631
        break;
 
632
#endif
 
633
      }
 
634
  
 
635
      if (header->id != (uint16)getpid())
 
636
        return;
 
637
  
 
638
      sequence = header->sequence;
 
639
    }
 
640
    break;
 
641
  
 
642
  case IPPROTO_UDP:
 
643
    if (header->type == timeexceededtype || header->type == unreachabletype) {
 
644
      switch ( af ) {
 
645
      case AF_INET:
 
646
 
 
647
        if ((size_t) num < sizeof(struct IPHeader) +
 
648
                           sizeof(struct ICMPHeader) +
 
649
                           sizeof (struct IPHeader) +
 
650
                           sizeof (struct UDPHeader))
 
651
          return;
 
652
        udpheader = (struct UDPHeader *)(packet + sizeof (struct IPHeader) +
 
653
                                                  sizeof (struct ICMPHeader) +
 
654
                                                  sizeof (struct IPHeader));
 
655
      break;
 
656
#ifdef ENABLE_IPV6
 
657
      case AF_INET6:
 
658
        if ( num < sizeof (struct ICMPHeader) +
 
659
                   sizeof (struct ip6_hdr) + sizeof (struct UDPHeader) )
 
660
          return;
 
661
        udpheader = (struct UDPHeader *) ( packet +
 
662
                                           sizeof (struct ICMPHeader) +
 
663
                                           sizeof (struct ip6_hdr) );
 
664
        break;
 
665
#endif
 
666
      }
 
667
      sequence = ntohs(udpheader->dstport);
 
668
    }
 
669
    break;
527
670
  }
 
671
 
 
672
  if (sequence)
 
673
    net_process_ping(sequence, (void *)fromaddress, now);
528
674
}
529
675
 
530
676
 
752
898
  return 0;
753
899
}
754
900
 
 
901
static void set_fd_flags(int fd)
 
902
{
 
903
#if defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
 
904
  int oldflags;
 
905
 
 
906
  oldflags = fcntl(fd, F_GETFD);
 
907
  if (oldflags == -1) {
 
908
    perror("Couldn't get fd's flags");
 
909
    return;
 
910
  }
 
911
  if (fcntl(fd, F_SETFD, oldflags | FD_CLOEXEC))
 
912
    perror("Couldn't set fd's flags");
 
913
#endif
 
914
}
755
915
 
756
916
int net_preopen(void) 
757
917
{
758
918
  int trueopt = 1;
759
919
 
760
920
#if !defined(IP_HDRINCL) && defined(IP_TOS) && defined(IP_TTL)
761
 
  sendsock4 = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
 
921
  sendsock4_icmp = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
 
922
  sendsock4_udp = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
762
923
#else
763
924
  sendsock4 = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
764
925
#endif
765
926
  if (sendsock4 < 0) 
766
927
    return -1;
767
928
#ifdef ENABLE_IPV6
768
 
  sendsock6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
 
929
  sendsock6_icmp = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
 
930
  sendsock6_udp = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP);
769
931
#endif
770
932
 
771
933
#ifdef IP_HDRINCL
780
942
  recvsock4 = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
781
943
  if (recvsock4 < 0)
782
944
    return -1;
 
945
  set_fd_flags(recvsock4);
783
946
#ifdef ENABLE_IPV6
784
947
  recvsock6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
785
948
#endif
 
949
  set_fd_flags(recvsock6);
786
950
 
787
951
  return 0;
788
952
}
789
953
 
790
 
 
 
954
 
 
955
int net_selectsocket(void)
 
956
{
 
957
#if !defined(IP_HDRINCL) && defined(IP_TOS) && defined(IP_TTL)
 
958
  switch ( mtrtype ) {
 
959
  case IPPROTO_ICMP:
 
960
    sendsock4 = sendsock4_icmp;
 
961
    break;
 
962
  case IPPROTO_UDP:
 
963
    sendsock4 = sendsock4_udp;
 
964
    break;
 
965
  }
 
966
#endif
 
967
  if (sendsock4 < 0)
 
968
    return -1;
 
969
#ifdef ENABLE_IPV6
 
970
  switch ( mtrtype ) {
 
971
  case IPPROTO_ICMP:
 
972
    sendsock6 = sendsock6_icmp;
 
973
    break;
 
974
  case IPPROTO_UDP:
 
975
    sendsock6 = sendsock6_udp;
 
976
    break;
 
977
  }
 
978
  if ((sendsock6 < 0) && (sendsock4 < 0))
 
979
    return -1;
 
980
#endif
 
981
 
 
982
 return 0;
 
983
}
 
984
 
 
985
 
791
986
int net_open(struct hostent * host) 
792
987
{
793
988
#ifdef ENABLE_IPV6
946
1141
 
947
1142
void net_close(void)
948
1143
{
949
 
  if (sendsock4 >= 0) close(sendsock4);
 
1144
  if (sendsock4 >= 0) {
 
1145
    close(sendsock4_icmp);
 
1146
    close(sendsock4_udp);
 
1147
  }
950
1148
  if (recvsock4 >= 0) close(recvsock4);
951
 
  if (sendsock6 >= 0) close(sendsock6);
 
1149
  if (sendsock6 >= 0) {
 
1150
    close(sendsock6_icmp);
 
1151
    close(sendsock6_udp);
 
1152
  }
952
1153
  if (recvsock6 >= 0) close(recvsock6);
953
1154
}
954
1155