Annotation of embedaddon/mtr/net.c, revision 1.1.1.1
1.1 misho 1: /*
2: mtr -- a network diagnostic tool
3: Copyright (C) 1997,1998 Matt Kimball
4:
5: This program is free software; you can redistribute it and/or modify
6: it under the terms of the GNU General Public License version 2 as
7: published by the Free Software Foundation.
8:
9: This program is distributed in the hope that it will be useful,
10: but WITHOUT ANY WARRANTY; without even the implied warranty of
11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12: GNU General Public License for more details.
13:
14: You should have received a copy of the GNU General Public License
15: along with this program; if not, write to the Free Software
16: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17: */
18:
19: #include <config.h>
20:
21: #if defined(HAVE_SYS_XTI_H)
22: #include <sys/xti.h>
23: #endif
24:
25: #include <sys/types.h>
26: #include <sys/time.h>
27: #include <sys/socket.h>
28: #include <sys/ioctl.h>
29: #include <sys/select.h>
30: #include <netinet/in.h>
31: #include <memory.h>
32: #include <unistd.h>
33: #ifdef HAVE_FCNTL_H
34: #include <fcntl.h>
35: #endif
36: #include <stdio.h>
37: #include <stdlib.h>
38: #include <math.h>
39: #include <errno.h>
40: #include <string.h>
41:
42: #include "mtr.h"
43: #include "net.h"
44: #include "display.h"
45: #include "dns.h"
46:
47: /* We can't rely on header files to provide this information, because
48: the fields have different names between, for instance, Linux and
49: Solaris */
50: struct ICMPHeader {
51: uint8 type;
52: uint8 code;
53: uint16 checksum;
54: uint16 id;
55: uint16 sequence;
56: };
57:
58: /* Structure of an UDP header. */
59: struct UDPHeader {
60: uint16 srcport;
61: uint16 dstport;
62: uint16 length;
63: uint16 checksum;
64: };
65:
66: /* Structure of an TCP header, as far as we need it. */
67: struct TCPHeader {
68: uint16 srcport;
69: uint16 dstport;
70: uint32 seq;
71: };
72:
73: /* Structure of an IPv4 UDP pseudoheader. */
74: struct UDPv4PHeader {
75: uint32 saddr;
76: uint32 daddr;
77: uint8 zero;
78: uint8 protocol;
79: uint16 len;
80: };
81:
82: /* Structure of an IP header. */
83: struct IPHeader {
84: uint8 version;
85: uint8 tos;
86: uint16 len;
87: uint16 id;
88: uint16 frag;
89: uint8 ttl;
90: uint8 protocol;
91: uint16 check;
92: uint32 saddr;
93: uint32 daddr;
94: };
95:
96:
97: #define ICMP_ECHO 8
98: #define ICMP_ECHOREPLY 0
99:
100: #define ICMP_TSTAMP 13
101: #define ICMP_TSTAMPREPLY 14
102:
103: #define ICMP_TIME_EXCEEDED 11
104: #define ICMP_UNREACHABLE 3
105:
106: #ifndef SOL_IP
107: #define SOL_IP 0
108: #endif
109:
110: struct nethost {
111: ip_t addr;
112: ip_t addrs[MAXPATH]; /* for multi paths byMin */
113: int xmit;
114: int returned;
115: int sent;
116: int up;
117: long long var;/* variance, could be overflowed */
118: int last;
119: int best;
120: int worst;
121: int avg; /* average: addByMin */
122: int gmean; /* geometirc mean: addByMin */
123: int jitter; /* current jitter, defined as t1-t0 addByMin */
124: /*int jbest;*/ /* min jitter, of cause it is 0, not needed */
125: int javg; /* avg jitter */
126: int jworst; /* max jitter */
127: int jinta; /* estimated variance,? rfc1889's "Interarrival Jitter" */
128: int transit;
129: int saved[SAVED_PINGS];
130: int saved_seq_offset;
131: struct mplslen mpls;
132: struct mplslen mplss[MAXPATH];
133: };
134:
135:
136: struct sequence {
137: int index;
138: int transit;
139: int saved_seq;
140: struct timeval time;
141: int socket;
142: };
143:
144:
145: /* Configuration parameter: How many queries to unknown hosts do we
146: send? (This limits the amount of traffic generated if a host is not
147: reachable) */
148: #define MAX_UNKNOWN_HOSTS 5
149:
150:
151: /* BSD-derived kernels use host byte order for the IP length and
152: offset fields when using raw sockets. We detect this automatically at
153: run-time and do the right thing. */
154: static int BSDfix = 0;
155:
156: static struct nethost host[MaxHost];
157: static struct sequence sequence[MaxSequence];
158: static struct timeval reset = { 0, 0 };
159:
160: int timestamp;
161: int sendsock4;
162: int sendsock4_icmp;
163: int sendsock4_udp;
164: int recvsock4;
165: int sendsock6;
166: int sendsock6_icmp;
167: int sendsock6_udp;
168: int recvsock6;
169: int sendsock;
170: int recvsock;
171:
172: #ifdef ENABLE_IPV6
173: struct sockaddr_storage sourcesockaddr_struct;
174: struct sockaddr_storage remotesockaddr_struct;
175: struct sockaddr_in6 * ssa6 = (struct sockaddr_in6 *) &sourcesockaddr_struct;
176: struct sockaddr_in6 * rsa6 = (struct sockaddr_in6 *) &remotesockaddr_struct;
177: #else
178: struct sockaddr_in sourcesockaddr_struct;
179: struct sockaddr_in remotesockaddr_struct;
180: #endif
181:
182: struct sockaddr * sourcesockaddr = (struct sockaddr *) &sourcesockaddr_struct;
183: struct sockaddr * remotesockaddr = (struct sockaddr *) &remotesockaddr_struct;
184: struct sockaddr_in * ssa4 = (struct sockaddr_in *) &sourcesockaddr_struct;
185: struct sockaddr_in * rsa4 = (struct sockaddr_in *) &remotesockaddr_struct;
186:
187: ip_t * sourceaddress;
188: ip_t * remoteaddress;
189:
190: /* XXX How do I code this to be IPV6 compatible??? */
191: #ifdef ENABLE_IPV6
192: char localaddr[INET6_ADDRSTRLEN];
193: #else
194: #ifndef INET_ADDRSTRLEN
195: #define INET_ADDRSTRLEN 16
196: #endif
197: char localaddr[INET_ADDRSTRLEN];
198: #endif
199:
200: static int batch_at = 0;
201: static int numhosts = 10;
202:
203: extern int fstTTL; /* initial hub(ttl) to ping byMin */
204: extern int maxTTL; /* last hub to ping byMin*/
205: extern int cpacketsize; /* packet size used by ping */
206: static int packetsize; /* packet size used by ping */
207: extern int bitpattern; /* packet bit pattern used by ping */
208: extern int tos; /* type of service set in ping packet*/
209: extern int af; /* address family of remote target */
210: extern int mtrtype; /* type of query packet used */
211: extern int remoteport; /* target port for TCP tracing */
212: extern int timeout; /* timeout for TCP connections */
213:
214: /* return the number of microseconds to wait before sending the next
215: ping */
216: int calc_deltatime (float waittime)
217: {
218: waittime /= numhosts;
219: return 1000000 * waittime;
220: }
221:
222:
223: /* This doesn't work for odd sz. I don't know enough about this to say
224: that this is wrong. It doesn't seem to cripple mtr though. -- REW */
225: int checksum(void *data, int sz)
226: {
227: unsigned short *ch;
228: unsigned int sum;
229:
230: sum = 0;
231: ch = data;
232: sz = sz / 2;
233: while (sz--) {
234: sum += *(ch++);
235: }
236:
237: sum = (sum >> 16) + (sum & 0xffff);
238:
239: return (~sum & 0xffff);
240: }
241:
242:
243: /* Prepend pseudoheader to the udp datagram and calculate checksum */
244: int udp_checksum(void *pheader, void *udata, int psize, int dsize)
245: {
246: unsigned int tsize = psize + dsize;
247: char csumpacket[tsize];
248: memset(csumpacket, (unsigned char) abs(bitpattern), abs(tsize));
249:
250: struct UDPv4PHeader *prepend = (struct UDPv4PHeader *) csumpacket;
251: struct UDPv4PHeader *udppheader = (struct UDPv4PHeader *) pheader;
252: prepend->saddr = udppheader->saddr;
253: prepend->daddr = udppheader->daddr;
254: prepend->zero = 0;
255: prepend->protocol = udppheader->protocol;
256: prepend->len = udppheader->len;
257:
258: struct UDPHeader *content = (struct UDPHeader *)(csumpacket + psize);
259: struct UDPHeader *udpdata = (struct UDPHeader *) udata;
260: content->srcport = udpdata->srcport;
261: content->dstport = udpdata->dstport;
262: content->length = udpdata->length;
263: content->checksum = udpdata->checksum;
264:
265: return checksum(csumpacket,tsize);
266: }
267:
268:
269: void save_sequence(int index, int seq)
270: {
271: sequence[seq].index = index;
272: sequence[seq].transit = 1;
273: sequence[seq].saved_seq = ++host[index].xmit;
274: memset(&sequence[seq].time, 0, sizeof(sequence[seq].time));
275:
276: host[index].transit = 1;
277: if (host[index].sent)
278: host[index].up = 0;
279: host[index].sent = 1;
280: net_save_xmit(index);
281: }
282:
283: int new_sequence(int index)
284: {
285: static int next_sequence = MinSequence;
286: int seq;
287:
288: seq = next_sequence++;
289: if (next_sequence >= MaxSequence)
290: next_sequence = MinSequence;
291:
292: save_sequence(index, seq);
293:
294: return seq;
295: }
296:
297: /* Attempt to connect to a TCP port with a TTL */
298: void net_send_tcp(int index)
299: {
300: int ttl, s;
301: int opt = 1;
302: int port;
303: struct sockaddr_storage local;
304: struct sockaddr_storage remote;
305: struct sockaddr_in *local4 = (struct sockaddr_in *) &local;
306: struct sockaddr_in6 *local6 = (struct sockaddr_in6 *) &local;
307: struct sockaddr_in *remote4 = (struct sockaddr_in *) &remote;
308: struct sockaddr_in6 *remote6 = (struct sockaddr_in6 *) &remote;
309: socklen_t len;
310:
311: ttl = index + 1;
312:
313: s = socket(af, SOCK_STREAM, 0);
314: if (s < 0) {
315: display_clear();
316: perror("socket()");
317: exit(EXIT_FAILURE);
318: }
319:
320: memset(&local, 0, sizeof (local));
321: memset(&remote, 0, sizeof (remote));
322: local.ss_family = af;
323: remote.ss_family = af;
324:
325: switch (af) {
326: case AF_INET:
327: addrcpy((void *) &local4->sin_addr, (void *) &ssa4->sin_addr, af);
328: addrcpy((void *) &remote4->sin_addr, (void *) remoteaddress, af);
329: remote4->sin_port = htons(remoteport);
330: break;
331: #ifdef ENABLE_IPV6
332: case AF_INET6:
333: addrcpy((void *) &local6->sin6_addr, (void *) &ssa6->sin6_addr, af);
334: addrcpy((void *) &remote6->sin6_addr, (void *) remoteaddress, af);
335: remote6->sin6_port = htons(remoteport);
336: break;
337: #endif
338: }
339:
340: if (bind(s, (struct sockaddr *) &local, sizeof (local))) {
341: display_clear();
342: perror("bind()");
343: exit(EXIT_FAILURE);
344: }
345:
346: len = sizeof (local);
347: if (getsockname(s, (struct sockaddr *) &local, &len)) {
348: display_clear();
349: perror("getsockname()");
350: exit(EXIT_FAILURE);
351: }
352:
353: opt = 1;
354: if (ioctl(s, FIONBIO, &opt)) {
355: display_clear();
356: perror("ioctl FIONBIO");
357: exit(EXIT_FAILURE);
358: }
359:
360: switch (af) {
361: case AF_INET:
362: if (setsockopt(s, IPPROTO_IP, IP_TTL, &ttl, sizeof (ttl))) {
363: display_clear();
364: perror("setsockopt IP_TTL");
365: exit(EXIT_FAILURE);
366: }
367: if (setsockopt(s, IPPROTO_IP, IP_TOS, &tos, sizeof (tos))) {
368: display_clear();
369: perror("setsockopt IP_TOS");
370: exit(EXIT_FAILURE);
371: }
372: break;
373: #ifdef ENABLE_IPV6
374: case AF_INET6:
375: if (setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof (ttl))) {
376: display_clear();
377: perror("setsockopt IP_TTL");
378: exit(EXIT_FAILURE);
379: }
380: break;
381: #endif
382: }
383:
384: switch (local.ss_family) {
385: case AF_INET:
386: port = ntohs(local4->sin_port);
387: break;
388: #ifdef ENABLE_IPV6
389: case AF_INET6:
390: port = ntohs(local6->sin6_port);
391: break;
392: #endif
393: default:
394: display_clear();
395: perror("unknown AF?");
396: exit(EXIT_FAILURE);
397: }
398:
399: save_sequence(index, port);
400: gettimeofday(&sequence[port].time, NULL);
401: sequence[port].socket = s;
402:
403: connect(s, (struct sockaddr *) &remote, sizeof (remote));
404: }
405:
406: /* Attempt to find the host at a particular number of hops away */
407: void net_send_query(int index)
408: {
409: if (mtrtype == IPPROTO_TCP) {
410: net_send_tcp(index);
411: return;
412: }
413:
414: /*ok char packet[sizeof(struct IPHeader) + sizeof(struct ICMPHeader)];*/
415: char packet[MAXPACKET];
416: struct IPHeader *ip = (struct IPHeader *) packet;
417: struct ICMPHeader *icmp = NULL;
418: struct UDPHeader *udp = NULL;
419: struct UDPv4PHeader *udpp = NULL;
420: uint16 mypid;
421:
422: /*ok int packetsize = sizeof(struct IPHeader) + sizeof(struct ICMPHeader) + datasize;*/
423: int rv;
424: static int first=1;
425: int ttl, iphsize = 0, echotype = 0, salen = 0;
426:
427: ttl = index + 1;
428:
429: #ifdef ENABLE_IPV6
430: /* offset for ipv6 checksum calculation */
431: int offset = 6;
432: #endif
433:
434: if ( packetsize < MINPACKET ) packetsize = MINPACKET;
435: if ( packetsize > MAXPACKET ) packetsize = MAXPACKET;
436:
437: memset(packet, (unsigned char) abs(bitpattern), abs(packetsize));
438:
439: switch ( af ) {
440: case AF_INET:
441: #if !defined(IP_HDRINCL) && defined(IP_TOS) && defined(IP_TTL)
442: iphsize = 0;
443: if ( setsockopt( sendsock, IPPROTO_IP, IP_TOS, &tos, sizeof tos ) ) {
444: perror( "setsockopt IP_TOS" );
445: exit( EXIT_FAILURE );
446: }
447: if ( setsockopt( sendsock, IPPROTO_IP, IP_TTL, &ttl, sizeof ttl ) ) {
448: perror( "setsockopt IP_TTL" );
449: exit( EXIT_FAILURE );
450: }
451: #else
452: iphsize = sizeof (struct IPHeader);
453:
454: ip->version = 0x45;
455: ip->tos = tos;
456: ip->len = BSDfix ? abs(packetsize): htons (abs(packetsize));
457: ip->id = 0;
458: ip->frag = 0; /* 1, if want to find mtu size? Min */
459: ip->ttl = ttl;
460: ip->protocol = mtrtype;
461: ip->check = 0;
462:
463: /* BSD needs the source address here, Linux & others do not... */
464: addrcpy( (void *) &(ip->saddr), (void *) &(ssa4->sin_addr), AF_INET );
465: addrcpy( (void *) &(ip->daddr), (void *) remoteaddress, AF_INET );
466: #endif
467: echotype = ICMP_ECHO;
468: salen = sizeof (struct sockaddr_in);
469: break;
470: #ifdef ENABLE_IPV6
471: case AF_INET6:
472: iphsize = 0;
473: if ( setsockopt( sendsock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
474: &ttl, sizeof ttl ) ) {
475: perror( "setsockopt IPV6_UNICAST_HOPS" );
476: exit( EXIT_FAILURE);
477: }
478: echotype = ICMP6_ECHO_REQUEST;
479: salen = sizeof (struct sockaddr_in6);
480: break;
481: #endif
482: }
483:
484: switch ( mtrtype ) {
485: case IPPROTO_ICMP:
486: icmp = (struct ICMPHeader *)(packet + iphsize);
487: icmp->type = echotype;
488: icmp->code = 0;
489: icmp->checksum = 0;
490: icmp->id = getpid();
491: icmp->sequence = new_sequence(index);
492: icmp->checksum = checksum(icmp, abs(packetsize) - iphsize);
493:
494: gettimeofday(&sequence[icmp->sequence].time, NULL);
495: break;
496:
497: case IPPROTO_UDP:
498: udp = (struct UDPHeader *)(packet + iphsize);
499: udp->checksum = 0;
500: mypid = (uint16)getpid();
501: if (mypid < MinPort)
502: mypid += MinPort;
503:
504: udp->srcport = htons(mypid);
505: udp->length = abs(packetsize) - iphsize;
506: if(!BSDfix)
507: udp->length = htons(udp->length);
508:
509: udp->dstport = new_sequence(index);
510: gettimeofday(&sequence[udp->dstport].time, NULL);
511: udp->dstport = htons(udp->dstport);
512: break;
513: }
514:
515: switch ( af ) {
516: case AF_INET:
517: switch ( mtrtype ) {
518: case IPPROTO_UDP:
519: /* checksum is not mandatory. only calculate if we know ip->saddr */
520: if (ip->saddr) {
521: udpp = (struct UDPv4PHeader *)(malloc(sizeof(struct UDPv4PHeader)));
522: udpp->saddr = ip->saddr;
523: udpp->daddr = ip->daddr;
524: udpp->protocol = ip->protocol;
525: udpp->len = udp->length;
526: udp->checksum = udp_checksum(udpp, udp, sizeof(struct UDPv4PHeader), abs(packetsize) - iphsize);
527: }
528: break;
529: }
530:
531: ip->check = checksum(packet, abs(packetsize));
532: break;
533: #ifdef ENABLE_IPV6
534: case AF_INET6:
535: switch ( mtrtype ) {
536: case IPPROTO_UDP:
537: /* kernel checksum calculation */
538: if ( setsockopt(sendsock, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, sizeof(offset)) ) {
539: perror( "setsockopt IPV6_CHECKSUM" );
540: exit( EXIT_FAILURE);
541: }
542: break;
543: }
544: break;
545: #endif
546: }
547:
548: rv = sendto(sendsock, packet, abs(packetsize), 0,
549: remotesockaddr, salen);
550: if (first && (rv < 0) && ((errno == EINVAL) || (errno == EMSGSIZE))) {
551: /* Try the first packet again using host byte order. */
552: ip->len = abs (packetsize);
553: rv = sendto(sendsock, packet, abs(packetsize), 0,
554: remotesockaddr, salen);
555: if (rv >= 0) {
556: BSDfix = 1;
557: }
558: }
559: first = 0;
560: }
561:
562:
563: /* We got a return on something we sent out. Record the address and
564: time. */
565: void net_process_ping(int seq, struct mplslen mpls, void * addr, struct timeval now)
566: {
567: int index;
568: int totusec;
569: int oldavg; /* usedByMin */
570: int oldjavg; /* usedByMin */
571: int i; /* usedByMin */
572: #ifdef ENABLE_IPV6
573: char addrcopy[sizeof(struct in6_addr)];
574: #else
575: char addrcopy[sizeof(struct in_addr)];
576: #endif
577:
578: /* Copy the from address ASAP because it can be overwritten */
579: addrcpy( (void *) &addrcopy, addr, af );
580:
581: if (seq < 0 || seq >= MaxSequence)
582: return;
583:
584: if (!sequence[seq].transit)
585: return;
586: sequence[seq].transit = 0;
587:
588: if (sequence[seq].socket > 0) {
589: close(sequence[seq].socket);
590: sequence[seq].socket = 0;
591: }
592:
593: index = sequence[seq].index;
594:
595: totusec = (now.tv_sec - sequence[seq].time.tv_sec ) * 1000000 +
596: (now.tv_usec - sequence[seq].time.tv_usec);
597: /* impossible? if( totusec < 0 ) totusec = 0 */;
598:
599: if ( addrcmp( (void *) &(host[index].addr),
600: (void *) &unspec_addr, af ) == 0 ) {
601: /* should be out of if as addr can change */
602: addrcpy( (void *) &(host[index].addr), addrcopy, af );
603: host[index].mpls = mpls;
604: display_rawhost(index, (void *) &(host[index].addr));
605:
606: /* multi paths */
607: addrcpy( (void *) &(host[index].addrs[0]), addrcopy, af );
608: host[index].mplss[0] = mpls;
609: } else {
610: for( i=0; i<MAXPATH; ) {
611: if( addrcmp( (void *) &(host[index].addrs[i]), (void *) &addrcopy,
612: af ) == 0 ||
613: addrcmp( (void *) &(host[index].addrs[i]),
614: (void *) &unspec_addr, af ) == 0 ) break;
615: i++;
616: }
617: if( addrcmp( (void *) &(host[index].addrs[i]), addrcopy, af ) != 0 &&
618: i<MAXPATH ) {
619: addrcpy( (void *) &(host[index].addrs[i]), addrcopy, af );
620: host[index].mplss[i] = mpls;
621: display_rawhost(index, (void *) &(host[index].addrs[i]));
622: }
623: }
624:
625: host[index].jitter = totusec - host[index].last;
626: if (host[index].jitter < 0 ) host[index].jitter = - host[index].jitter;
627: host[index].last = totusec;
628:
629: if (host[index].returned < 1) {
630: host[index].best = host[index].worst = host[index].gmean = totusec;
631: host[index].avg = host[index].var = 0;
632:
633: host[index].jitter = host[index].jworst = host[index].jinta= 0;
634: }
635:
636: /* some time best can be too good to be true, experienced
637: * at least in linux 2.4.x.
638: * safe guard 1) best[index]>=best[index-1] if index>0
639: * 2) best >= average-20,000 usec (good number?)
640: if (index > 0) {
641: if (totusec < host[index].best &&
642: totusec>= host[index-1].best) host[index].best = totusec;
643: } else {
644: if(totusec < host[index].best) host[index].best = totusec;
645: }
646: */
647: if (totusec < host[index].best ) host[index].best = totusec;
648: if (totusec > host[index].worst) host[index].worst = totusec;
649:
650: if (host[index].jitter > host[index].jworst)
651: host[index].jworst = host[index].jitter;
652:
653: host[index].returned++;
654: oldavg = host[index].avg;
655: host[index].avg += (totusec - oldavg +.0) / host[index].returned;
656: host[index].var += (totusec - oldavg +.0) * (totusec - host[index].avg) / 1000000;
657:
658: oldjavg = host[index].javg;
659: host[index].javg += (host[index].jitter - oldjavg) / host[index].returned;
660: /* below algorithm is from rfc1889, A.8 */
661: host[index].jinta += host[index].jitter - ((host[index].jinta + 8) >> 4);
662:
663: if ( host[index].returned > 1 )
664: host[index].gmean = pow( (double) host[index].gmean, (host[index].returned-1.0)/host[index].returned )
665: * pow( (double) totusec, 1.0/host[index].returned );
666: host[index].sent = 0;
667: host[index].up = 1;
668: host[index].transit = 0;
669:
670: net_save_return(index, sequence[seq].saved_seq, totusec);
671: display_rawping(index, totusec);
672: }
673:
674:
675: /* We know a packet has come in, because the main select loop has called us,
676: now we just need to read it, see if it is for us, and if it is a reply
677: to something we sent, then call net_process_ping() */
678: void net_process_return(void)
679: {
680: char packet[MAXPACKET];
681: #ifdef ENABLE_IPV6
682: struct sockaddr_storage fromsockaddr_struct;
683: struct sockaddr_in6 * fsa6 = (struct sockaddr_in6 *) &fromsockaddr_struct;
684: #else
685: struct sockaddr_in fromsockaddr_struct;
686: #endif
687: struct sockaddr * fromsockaddr = (struct sockaddr *) &fromsockaddr_struct;
688: struct sockaddr_in * fsa4 = (struct sockaddr_in *) &fromsockaddr_struct;
689: socklen_t fromsockaddrsize;
690: int num;
691: struct ICMPHeader *header = NULL;
692: struct UDPHeader *udpheader = NULL;
693: struct TCPHeader *tcpheader = NULL;
694: struct timeval now;
695: ip_t * fromaddress = NULL;
696: int echoreplytype = 0, timeexceededtype = 0, unreachabletype = 0;
697: int sequence = 0;
698:
699: /* MPLS decoding */
700: struct mplslen mpls;
701: mpls.labels = 0;
702:
703: gettimeofday(&now, NULL);
704: switch ( af ) {
705: case AF_INET:
706: fromsockaddrsize = sizeof (struct sockaddr_in);
707: fromaddress = (ip_t *) &(fsa4->sin_addr);
708: echoreplytype = ICMP_ECHOREPLY;
709: timeexceededtype = ICMP_TIME_EXCEEDED;
710: unreachabletype = ICMP_UNREACHABLE;
711: break;
712: #ifdef ENABLE_IPV6
713: case AF_INET6:
714: fromsockaddrsize = sizeof (struct sockaddr_in6);
715: fromaddress = (ip_t *) &(fsa6->sin6_addr);
716: echoreplytype = ICMP6_ECHO_REPLY;
717: timeexceededtype = ICMP6_TIME_EXCEEDED;
718: unreachabletype = ICMP6_DST_UNREACH;
719: break;
720: #endif
721: }
722:
723: num = recvfrom(recvsock, packet, MAXPACKET, 0,
724: fromsockaddr, &fromsockaddrsize);
725:
726: switch ( af ) {
727: case AF_INET:
728: if((size_t) num < sizeof(struct IPHeader) + sizeof(struct ICMPHeader))
729: return;
730: header = (struct ICMPHeader *)(packet + sizeof(struct IPHeader));
731: break;
732: #ifdef ENABLE_IPV6
733: case AF_INET6:
734: if(num < sizeof(struct ICMPHeader))
735: return;
736:
737: header = (struct ICMPHeader *) packet;
738: break;
739: #endif
740: }
741:
742: switch ( mtrtype ) {
743: case IPPROTO_ICMP:
744: if (header->type == echoreplytype) {
745: if(header->id != (uint16)getpid())
746: return;
747:
748: sequence = header->sequence;
749: } else if (header->type == timeexceededtype) {
750: switch ( af ) {
751: case AF_INET:
752:
753: if ((size_t) num < sizeof(struct IPHeader) +
754: sizeof(struct ICMPHeader) +
755: sizeof (struct IPHeader) +
756: sizeof (struct ICMPHeader))
757: return;
758: header = (struct ICMPHeader *)(packet + sizeof (struct IPHeader) +
759: sizeof (struct ICMPHeader) +
760: sizeof (struct IPHeader));
761:
762: if(num > 160)
763: decodempls(num, packet, &mpls, 156);
764:
765: break;
766: #ifdef ENABLE_IPV6
767: case AF_INET6:
768: if ( num < sizeof (struct ICMPHeader) +
769: sizeof (struct ip6_hdr) + sizeof (struct ICMPHeader) )
770: return;
771: header = (struct ICMPHeader *) ( packet +
772: sizeof (struct ICMPHeader) +
773: sizeof (struct ip6_hdr) );
774:
775: if(num > 140)
776: decodempls(num, packet, &mpls, 136);
777:
778: break;
779: #endif
780: }
781:
782: if (header->id != (uint16)getpid())
783: return;
784:
785: sequence = header->sequence;
786: }
787: break;
788:
789: case IPPROTO_UDP:
790: if (header->type == timeexceededtype || header->type == unreachabletype) {
791: switch ( af ) {
792: case AF_INET:
793:
794: if ((size_t) num < sizeof(struct IPHeader) +
795: sizeof(struct ICMPHeader) +
796: sizeof (struct IPHeader) +
797: sizeof (struct UDPHeader))
798: return;
799: udpheader = (struct UDPHeader *)(packet + sizeof (struct IPHeader) +
800: sizeof (struct ICMPHeader) +
801: sizeof (struct IPHeader));
802:
803: if(num > 160)
804: decodempls(num, packet, &mpls, 156);
805:
806: break;
807: #ifdef ENABLE_IPV6
808: case AF_INET6:
809: if ( num < sizeof (struct ICMPHeader) +
810: sizeof (struct ip6_hdr) + sizeof (struct UDPHeader) )
811: return;
812: udpheader = (struct UDPHeader *) ( packet +
813: sizeof (struct ICMPHeader) +
814: sizeof (struct ip6_hdr) );
815:
816: if(num > 140)
817: decodempls(num, packet, &mpls, 136);
818:
819: break;
820: #endif
821: }
822: sequence = ntohs(udpheader->dstport);
823: }
824: break;
825:
826: case IPPROTO_TCP:
827: if (header->type == timeexceededtype || header->type == unreachabletype) {
828: switch ( af ) {
829: case AF_INET:
830:
831: if ((size_t) num < sizeof(struct IPHeader) +
832: sizeof(struct ICMPHeader) +
833: sizeof (struct IPHeader) +
834: sizeof (struct TCPHeader))
835: return;
836: tcpheader = (struct TCPHeader *)(packet + sizeof (struct IPHeader) +
837: sizeof (struct ICMPHeader) +
838: sizeof (struct IPHeader));
839:
840: if(num > 160)
841: decodempls(num, packet, &mpls, 156);
842:
843: break;
844: #ifdef ENABLE_IPV6
845: case AF_INET6:
846: if ( num < sizeof (struct ICMPHeader) +
847: sizeof (struct ip6_hdr) + sizeof (struct TCPHeader) )
848: return;
849: tcpheader = (struct TCPHeader *) ( packet +
850: sizeof (struct ICMPHeader) +
851: sizeof (struct ip6_hdr) );
852:
853: if(num > 140)
854: decodempls(num, packet, &mpls, 136);
855:
856: break;
857: #endif
858: }
859: sequence = ntohs(tcpheader->srcport);
860: }
861: break;
862: }
863:
864: if (sequence)
865: net_process_ping (sequence, mpls, (void *) fromaddress, now);
866: }
867:
868:
869: ip_t *net_addr(int at)
870: {
871: return (ip_t *)&(host[at].addr);
872: }
873:
874:
875: ip_t *net_addrs(int at, int i)
876: {
877: return (ip_t *)&(host[at].addrs[i]);
878: }
879:
880: void *net_mpls(int at)
881: {
882: return (struct mplslen *)&(host[at].mplss);
883: }
884:
885: void *net_mplss(int at, int i)
886: {
887: return (struct mplslen *)&(host[at].mplss[i]);
888: }
889:
890: int net_loss(int at)
891: {
892: if ((host[at].xmit - host[at].transit) == 0)
893: return 0;
894: /* times extra 1000 */
895: return 1000*(100 - (100.0 * host[at].returned / (host[at].xmit - host[at].transit)) );
896: }
897:
898:
899: int net_drop(int at)
900: {
901: return (host[at].xmit - host[at].transit) - host[at].returned;
902: }
903:
904:
905: int net_last(int at)
906: {
907: return (host[at].last);
908: }
909:
910:
911: int net_best(int at)
912: {
913: return (host[at].best);
914: }
915:
916:
917: int net_worst(int at)
918: {
919: return (host[at].worst);
920: }
921:
922:
923: int net_avg(int at)
924: {
925: return (host[at].avg);
926: }
927:
928:
929: int net_gmean(int at)
930: {
931: return (host[at].gmean);
932: }
933:
934:
935: int net_stdev(int at)
936: {
937: if( host[at].returned > 1 ) {
938: return ( 1000.0 * sqrt( host[at].var/(host[at].returned -1.0) ) );
939: } else {
940: return( 0 );
941: }
942: }
943:
944:
945: int net_jitter(int at)
946: {
947: return (host[at].jitter);
948: }
949:
950:
951: int net_jworst(int at)
952: {
953: return (host[at].jworst);
954: }
955:
956:
957: int net_javg(int at)
958: {
959: return (host[at].javg);
960: }
961:
962:
963: int net_jinta(int at)
964: {
965: return (host[at].jinta);
966: }
967:
968:
969: int net_max(void)
970: {
971: int at;
972: int max;
973:
974: max = 0;
975: /* for(at = 0; at < MaxHost-2; at++) { */
976: for(at = 0; at < maxTTL-1; at++) {
977: if ( addrcmp( (void *) &(host[at].addr),
978: (void *) remoteaddress, af ) == 0 ) {
979: return at + 1;
980: } else if ( addrcmp( (void *) &(host[at].addr),
981: (void *) &unspec_addr, af ) != 0 ) {
982: max = at + 2;
983: }
984: }
985:
986: return max;
987: }
988:
989:
990: int net_min (void)
991: {
992: return ( fstTTL - 1 );
993: }
994:
995:
996: int net_returned(int at)
997: {
998: return host[at].returned;
999: }
1000:
1001:
1002: int net_xmit(int at)
1003: {
1004: return host[at].xmit;
1005: }
1006:
1007:
1008: int net_transit(int at)
1009: {
1010: return host[at].transit;
1011: }
1012:
1013:
1014: int net_up(int at)
1015: {
1016: return host[at].up;
1017: }
1018:
1019:
1020: char * net_localaddr (void)
1021: {
1022: return localaddr;
1023: }
1024:
1025:
1026: void net_end_transit(void)
1027: {
1028: int at;
1029:
1030: for(at = 0; at < MaxHost; at++) {
1031: host[at].transit = 0;
1032: }
1033: }
1034:
1035: int net_send_batch(void)
1036: {
1037: int n_unknown=0, i;
1038:
1039: /* randomized packet size and/or bit pattern if packetsize<0 and/or
1040: bitpattern<0. abs(packetsize) and/or abs(bitpattern) will be used
1041: */
1042: if( batch_at < fstTTL ) {
1043: if( cpacketsize < 0 ) {
1044: /* Someone used a formula here that tried to correct for the
1045: "end-error" in "rand()". By "end-error" I mean that if you
1046: have a range for "rand()" that runs to 32768, and the
1047: destination range is 10000, you end up with 4 out of 32768
1048: 0-2768's and only 3 out of 32768 for results 2769 .. 9999.
1049: As our detination range (in the example 10000) is much
1050: smaller (reasonable packet sizes), and our rand() range much
1051: larger, this effect is insignificant. Oh! That other formula
1052: didn't work. */
1053: packetsize = MINPACKET + rand () % (-cpacketsize - MINPACKET);
1054: } else {
1055: packetsize = cpacketsize;
1056: }
1057: if( bitpattern < 0 ) {
1058: bitpattern = - (int)(256 + 255*(rand()/(RAND_MAX+0.1)));
1059: }
1060: }
1061:
1062: /* printf ("cpacketsize = %d, packetsize = %d\n", cpacketsize, packetsize); */
1063:
1064: net_send_query(batch_at);
1065:
1066: for (i=fstTTL-1;i<batch_at;i++) {
1067: if ( addrcmp( (void *) &(host[i].addr), (void *) &unspec_addr, af ) == 0 )
1068: n_unknown++;
1069:
1070: /* The second condition in the next "if" statement was added in mtr-0.56,
1071: but I don't remember why. It makes mtr stop skipping sections of unknown
1072: hosts. Removed in 0.65.
1073: If the line proves neccesary, it should at least NOT trigger that line
1074: when host[i].addr == 0 */
1075: if ( ( addrcmp( (void *) &(host[i].addr),
1076: (void *) remoteaddress, af ) == 0 )
1077: /* || (host[i].addr == host[batch_at].addr) */)
1078: n_unknown = MaxHost; /* Make sure we drop into "we should restart" */
1079: }
1080:
1081: if ( /* success in reaching target */
1082: ( addrcmp( (void *) &(host[batch_at].addr),
1083: (void *) remoteaddress, af ) == 0 ) ||
1084: /* fail in consecuitive MAX_UNKNOWN_HOSTS (firewall?) */
1085: (n_unknown > MAX_UNKNOWN_HOSTS) ||
1086: /* or reach limit */
1087: (batch_at >= maxTTL-1)) {
1088: numhosts = batch_at+1;
1089: batch_at = fstTTL - 1;
1090: return 1;
1091: }
1092:
1093: batch_at++;
1094: return 0;
1095: }
1096:
1097:
1098: static void set_fd_flags(int fd)
1099: {
1100: #if defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
1101: int oldflags;
1102:
1103: if (fd < 0) return;
1104:
1105: oldflags = fcntl(fd, F_GETFD);
1106: if (oldflags == -1) {
1107: perror("Couldn't get fd's flags");
1108: return;
1109: }
1110: if (fcntl(fd, F_SETFD, oldflags | FD_CLOEXEC))
1111: perror("Couldn't set fd's flags");
1112: #endif
1113: }
1114:
1115: int net_preopen(void)
1116: {
1117: int trueopt = 1;
1118:
1119: #if !defined(IP_HDRINCL) && defined(IP_TOS) && defined(IP_TTL)
1120: sendsock4_icmp = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
1121: sendsock4_udp = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
1122: #else
1123: sendsock4 = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
1124: #endif
1125: if (sendsock4 < 0)
1126: return -1;
1127: #ifdef ENABLE_IPV6
1128: sendsock6_icmp = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
1129: sendsock6_udp = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP);
1130: #endif
1131:
1132: #ifdef IP_HDRINCL
1133: /* FreeBSD wants this to avoid sending out packets with protocol type RAW
1134: to the network. */
1135: if (setsockopt(sendsock4, SOL_IP, IP_HDRINCL, &trueopt, sizeof(trueopt))) {
1136: perror("setsockopt(IP_HDRINCL,1)");
1137: return -1;
1138: }
1139: #endif /* IP_HDRINCL */
1140:
1141: recvsock4 = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
1142: if (recvsock4 < 0)
1143: return -1;
1144: set_fd_flags(recvsock4);
1145: #ifdef ENABLE_IPV6
1146: recvsock6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
1147: if (recvsock6 >= 0)
1148: set_fd_flags(recvsock6);
1149: #endif
1150:
1151: return 0;
1152: }
1153:
1154:
1155: int net_selectsocket(void)
1156: {
1157: #if !defined(IP_HDRINCL) && defined(IP_TOS) && defined(IP_TTL)
1158: switch ( mtrtype ) {
1159: case IPPROTO_ICMP:
1160: sendsock4 = sendsock4_icmp;
1161: break;
1162: case IPPROTO_UDP:
1163: sendsock4 = sendsock4_udp;
1164: break;
1165: }
1166: #endif
1167: if (sendsock4 < 0)
1168: return -1;
1169: #ifdef ENABLE_IPV6
1170: switch ( mtrtype ) {
1171: case IPPROTO_ICMP:
1172: sendsock6 = sendsock6_icmp;
1173: break;
1174: case IPPROTO_UDP:
1175: sendsock6 = sendsock6_udp;
1176: break;
1177: }
1178: if ((sendsock6 < 0) && (sendsock4 < 0))
1179: return -1;
1180: #endif
1181:
1182: return 0;
1183: }
1184:
1185:
1186: int net_open(struct hostent * host)
1187: {
1188: #ifdef ENABLE_IPV6
1189: struct sockaddr_storage name_struct;
1190: #else
1191: struct sockaddr_in name_struct;
1192: #endif
1193: struct sockaddr * name = (struct sockaddr *) &name_struct;
1194: socklen_t len;
1195:
1196: net_reset();
1197:
1198: remotesockaddr->sa_family = host->h_addrtype;
1199:
1200: switch ( host->h_addrtype ) {
1201: case AF_INET:
1202: sendsock = sendsock4;
1203: recvsock = recvsock4;
1204: addrcpy( (void *) &(rsa4->sin_addr), host->h_addr, AF_INET );
1205: sourceaddress = (ip_t *) &(ssa4->sin_addr);
1206: remoteaddress = (ip_t *) &(rsa4->sin_addr);
1207: break;
1208: #ifdef ENABLE_IPV6
1209: case AF_INET6:
1210: if (sendsock6 < 0 || recvsock6 < 0) {
1211: fprintf( stderr, "Could not open IPv6 socket\n" );
1212: exit( EXIT_FAILURE );
1213: }
1214: sendsock = sendsock6;
1215: recvsock = recvsock6;
1216: addrcpy( (void *) &(rsa6->sin6_addr), host->h_addr, AF_INET6 );
1217: sourceaddress = (ip_t *) &(ssa6->sin6_addr);
1218: remoteaddress = (ip_t *) &(rsa6->sin6_addr);
1219: break;
1220: #endif
1221: default:
1222: fprintf( stderr, "net_open bad address type\n" );
1223: exit( EXIT_FAILURE );
1224: }
1225:
1226: len = sizeof name_struct;
1227: getsockname (recvsock, name, &len);
1228: sockaddrtop( name, localaddr, sizeof localaddr );
1229: #if 0
1230: printf ("got localaddr: %s\n", localaddr);
1231: #endif
1232:
1233: return 0;
1234: }
1235:
1236:
1237: void net_reopen(struct hostent * addr)
1238: {
1239: int at;
1240:
1241: for(at = 0; at < MaxHost; at++) {
1242: memset(&host[at], 0, sizeof(host[at]));
1243: }
1244:
1245: remotesockaddr->sa_family = addr->h_addrtype;
1246: addrcpy( (void *) remoteaddress, addr->h_addr, addr->h_addrtype );
1247:
1248: switch ( addr->h_addrtype ) {
1249: case AF_INET:
1250: addrcpy( (void *) &(rsa4->sin_addr), addr->h_addr, AF_INET );
1251: break;
1252: #ifdef ENABLE_IPV6
1253: case AF_INET6:
1254: addrcpy( (void *) &(rsa6->sin6_addr), addr->h_addr, AF_INET6 );
1255: break;
1256: #endif
1257: default:
1258: fprintf( stderr, "net_reopen bad address type\n" );
1259: exit( EXIT_FAILURE );
1260: }
1261:
1262: net_reset ();
1263: net_send_batch();
1264: }
1265:
1266:
1267: void net_reset(void)
1268: {
1269: int at;
1270: int i;
1271:
1272: batch_at = fstTTL - 1; /* above replacedByMin */
1273: numhosts = 10;
1274:
1275: for (at = 0; at < MaxHost; at++) {
1276: host[at].xmit = 0;
1277: host[at].transit = 0;
1278: host[at].returned = 0;
1279: host[at].sent = 0;
1280: host[at].up = 0;
1281: host[at].last = 0;
1282: host[at].avg = 0;
1283: host[at].best = 0;
1284: host[at].worst = 0;
1285: host[at].gmean = 0;
1286: host[at].var = 0;
1287: host[at].jitter = 0;
1288: host[at].javg = 0;
1289: host[at].jworst = 0;
1290: host[at].jinta = 0;
1291: for (i=0; i<SAVED_PINGS; i++) {
1292: host[at].saved[i] = -2; /* unsent */
1293: }
1294: host[at].saved_seq_offset = -SAVED_PINGS+2;
1295: }
1296:
1297: for (at = 0; at < MaxSequence; at++) {
1298: sequence[at].transit = 0;
1299: if (sequence[at].socket > 0) {
1300: close(sequence[at].socket);
1301: sequence[at].socket = 0;
1302: }
1303: }
1304:
1305: gettimeofday(&reset, NULL);
1306: }
1307:
1308:
1309: int net_set_interfaceaddress (char *InterfaceAddress)
1310: {
1311: int len = 0;
1312:
1313: if (!InterfaceAddress) return 0;
1314:
1315: sourcesockaddr->sa_family = af;
1316: switch ( af ) {
1317: case AF_INET:
1318: ssa4->sin_port = 0;
1319: if ( inet_aton( InterfaceAddress, &(ssa4->sin_addr) ) < 1 ) {
1320: fprintf( stderr, "mtr: bad interface address: %s\n", InterfaceAddress );
1321: return( 1 );
1322: }
1323: len = sizeof (struct sockaddr);
1324: break;
1325: #ifdef ENABLE_IPV6
1326: case AF_INET6:
1327: ssa6->sin6_port = 0;
1328: if ( inet_pton( af, InterfaceAddress, &(ssa6->sin6_addr) ) < 1 ) {
1329: fprintf( stderr, "mtr: bad interface address: %s\n", InterfaceAddress );
1330: return( 1 );
1331: }
1332: len = sizeof (struct sockaddr_in6);
1333: break;
1334: #endif
1335: }
1336:
1337: if ( bind( sendsock, sourcesockaddr, len ) == -1 ) {
1338: perror("mtr: failed to bind to interface");
1339: return( 1 );
1340: }
1341: return 0;
1342: }
1343:
1344:
1345:
1346: void net_close(void)
1347: {
1348: if (sendsock4 >= 0) {
1349: close(sendsock4_icmp);
1350: close(sendsock4_udp);
1351: }
1352: if (recvsock4 >= 0) close(recvsock4);
1353: if (sendsock6 >= 0) {
1354: close(sendsock6_icmp);
1355: close(sendsock6_udp);
1356: }
1357: if (recvsock6 >= 0) close(recvsock6);
1358: }
1359:
1360:
1361: int net_waitfd(void)
1362: {
1363: return recvsock;
1364: }
1365:
1366:
1367: int* net_saved_pings(int at)
1368: {
1369: return host[at].saved;
1370: }
1371:
1372:
1373: void net_save_increment(void)
1374: {
1375: int at;
1376: for (at = 0; at < MaxHost; at++) {
1377: memmove(host[at].saved, host[at].saved+1, (SAVED_PINGS-1)*sizeof(int));
1378: host[at].saved[SAVED_PINGS-1] = -2;
1379: host[at].saved_seq_offset += 1;
1380: }
1381: }
1382:
1383:
1384: void net_save_xmit(int at)
1385: {
1386: if (host[at].saved[SAVED_PINGS-1] != -2)
1387: net_save_increment();
1388: host[at].saved[SAVED_PINGS-1] = -1;
1389: }
1390:
1391:
1392: void net_save_return(int at, int seq, int ms)
1393: {
1394: int idx;
1395: idx = seq - host[at].saved_seq_offset;
1396: if (idx < 0 || idx > SAVED_PINGS) {
1397: return;
1398: }
1399: host[at].saved[idx] = ms;
1400: }
1401:
1402: /* Similar to inet_ntop but uses a sockaddr as it's argument. */
1403: void sockaddrtop( struct sockaddr * saddr, char * strptr, size_t len ) {
1404: struct sockaddr_in * sa4;
1405: #ifdef ENABLE_IPV6
1406: struct sockaddr_in6 * sa6;
1407: #endif
1408:
1409: switch ( saddr->sa_family ) {
1410: case AF_INET:
1411: sa4 = (struct sockaddr_in *) saddr;
1412: strncpy( strptr, inet_ntoa( sa4->sin_addr ), len - 1 );
1413: strptr[ len - 1 ] = '\0';
1414: return;
1415: #ifdef ENABLE_IPV6
1416: case AF_INET6:
1417: sa6 = (struct sockaddr_in6 *) saddr;
1418: inet_ntop( sa6->sin6_family, &(sa6->sin6_addr), strptr, len );
1419: return;
1420: #endif
1421: default:
1422: fprintf( stderr, "sockaddrtop unknown address type\n" );
1423: strptr[0] = '\0';
1424: return;
1425: }
1426: }
1427:
1428: /* Address comparison. */
1429: int addrcmp( char * a, char * b, int af ) {
1430: int rc = -1;
1431:
1432: switch ( af ) {
1433: case AF_INET:
1434: rc = memcmp( a, b, sizeof (struct in_addr) );
1435: break;
1436: #ifdef ENABLE_IPV6
1437: case AF_INET6:
1438: rc = memcmp( a, b, sizeof (struct in6_addr) );
1439: break;
1440: #endif
1441: }
1442:
1443: return rc;
1444: }
1445:
1446: /* Address copy. */
1447: void addrcpy( char * a, char * b, int af ) {
1448:
1449: switch ( af ) {
1450: case AF_INET:
1451: memcpy( a, b, sizeof (struct in_addr) );
1452: break;
1453: #ifdef ENABLE_IPV6
1454: case AF_INET6:
1455: memcpy( a, b, sizeof (struct in6_addr) );
1456: break;
1457: #endif
1458: }
1459: }
1460:
1461: /* Decode MPLS */
1462: void decodempls(int num, char *packet, struct mplslen *mpls, int offset) {
1463:
1464: int i;
1465: unsigned int ext_ver, ext_res, ext_chk, obj_hdr_len;
1466: u_char obj_hdr_class, obj_hdr_type;
1467:
1468: /* loosely derived from the traceroute-nanog.c
1469: * decoding by Jorge Boncompte */
1470: ext_ver = packet[offset]>>4;
1471: ext_res = (packet[offset]&15)+ packet[offset+1];
1472: ext_chk = ((unsigned int)packet[offset+2]<<8)+packet[offset+3];
1473:
1474: /* Check for ICMP extension header */
1475: if (ext_ver == 2 && ext_res == 0 && ext_chk != 0 && num >= (offset+6)) {
1476: obj_hdr_len = ((int)packet[offset+4]<<8)+packet[offset+5];
1477: obj_hdr_class = packet[offset+6];
1478: obj_hdr_type = packet[offset+7];
1479:
1480: /* make sure we have an MPLS extension */
1481: if (obj_hdr_len >= 8 && obj_hdr_class == 1 && obj_hdr_type == 1) {
1482: /* how many labels do we have? will be at least 1 */
1483: mpls->labels = (obj_hdr_len-4)/4;
1484:
1485: /* save all label objects */
1486: for(i=0; (i<mpls->labels) && (i < MAXLABELS) && (num >= (offset+8)+(i*4)); i++) {
1487:
1488: /* piece together the 20 byte label value */
1489: mpls->label[i] = ((unsigned long) (packet[(offset+8)+(i*4)] << 12 & 0xff000) +
1490: (unsigned int) (packet[(offset+9)+(i*4)] << 4 & 0xff0) +
1491: (packet[(offset+10)+(i*4)] >> 4 & 0xf));
1492: mpls->exp[i] = (packet[(offset+10)+(i*4)] >> 1) & 0x7;
1493: mpls->s[i] = (packet[(offset+10)+(i*4)] & 0x1); /* should be 1 if only one label */
1494: mpls->ttl[i] = packet[(offset+11)+(i*4)];
1495: }
1496: }
1497: }
1498: }
1499:
1500: /* Add open sockets to select() */
1501: void net_add_fds(fd_set *writefd, int *maxfd)
1502: {
1503: int at, fd;
1504: for (at = 0; at < MaxSequence; at++) {
1505: fd = sequence[at].socket;
1506: if (fd > 0) {
1507: FD_SET(fd, writefd);
1508: if (fd >= *maxfd)
1509: *maxfd = fd + 1;
1510: }
1511: }
1512: }
1513:
1514: /* check if we got connection or error on any fds */
1515: void net_process_fds(fd_set *writefd)
1516: {
1517: int at, fd, r;
1518: struct timeval now;
1519: uint64_t unow, utime;
1520:
1521: /* Can't do MPLS decoding */
1522: struct mplslen mpls;
1523: mpls.labels = 0;
1524:
1525: gettimeofday(&now, NULL);
1526: unow = now.tv_sec * 1000000L + now.tv_usec;
1527:
1528: for (at = 0; at < MaxSequence; at++) {
1529: fd = sequence[at].socket;
1530: if (fd > 0 && FD_ISSET(fd, writefd)) {
1531: r = write(fd, "G", 1);
1532: /* if write was successful, or connection refused we have
1533: * (probably) reached the remote address. Anything else happens to the
1534: * connection, we write it off to avoid leaking sockets */
1535: if (r == 1 || errno == ECONNREFUSED)
1536: net_process_ping(at, mpls, remoteaddress, now);
1537: else if (errno != EAGAIN) {
1538: close(fd);
1539: sequence[at].socket = 0;
1540: }
1541: }
1542: if (fd > 0) {
1543: utime = sequence[at].time.tv_sec * 1000000L + sequence[at].time.tv_usec;
1544: if (unow - utime > timeout) {
1545: close(fd);
1546: sequence[at].socket = 0;
1547: }
1548: }
1549: }
1550: }
1551:
1552: /* for GTK frontend */
1553: void net_harvest_fds(void)
1554: {
1555: fd_set writefd;
1556: int maxfd = 0;
1557: struct timeval tv;
1558:
1559: FD_ZERO(&writefd);
1560: tv.tv_sec = 0;
1561: tv.tv_usec = 0;
1562: net_add_fds(&writefd, &maxfd);
1563: select(maxfd, NULL, &writefd, NULL, &tv);
1564: net_process_fds(&writefd);
1565: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>