/*int maxTTL = MaxHost-1; */ /* max you can go is 255 hops */
int maxTTL = 30; /* inline with traceroute */
/* end ttl window stuff. */
-int remoteport = 80; /* for TCP tracing */
+int remoteport = 0; /* for TCP tracing */
+int localport = 0; /* for UDP tracing */
int tcp_timeout = 10 * 1000000; /* for TCP tracing */
{ "udp", 0, 0, 'u' }, /* UDP (default is ICMP) */
{ "tcp", 0, 0, 'T' }, /* TCP (default is ICMP) */
{ "sctp", 0, 0, 'S' }, /* SCTP (default is ICMP) */
- { "port", 1, 0, 'P' }, /* target port number for TCP */
+ { "port", 1, 0, 'P' }, /* target port number for TCP/SCTP/UDP */
+ { "localport", 1, 0, 'L' }, /* source port number for UDP */
{ "timeout", 1, 0, 'Z' }, /* timeout for TCP sockets */
#ifdef SO_MARK
{ "mark", 1, 0, 'M' }, /* use SO_MARK */
opt = 0;
while(1) {
opt = getopt_long(argc, argv,
- "hv46F:rwxtglCpnbo:y:zi:c:s:B:Q:ea:f:m:uTSP:Z:M:", long_options, NULL);
+ "hv46F:rwxtglCpnbo:y:zi:c:s:B:Q:ea:f:m:uTSP:L:Z:M:", long_options, NULL);
if(opt == -1)
break;
fprintf(stderr, "-u , -T and -S are mutually exclusive.\n");
exit(EXIT_FAILURE);
}
+ if (!remoteport) {
+ remoteport = 80;
+ }
mtrtype = IPPROTO_TCP;
break;
case 'S':
fprintf(stderr, "-u , -T and -S are mutually exclusive.\n");
exit(EXIT_FAILURE);
}
+ if (!remoteport) {
+ remoteport = 80;
+ }
mtrtype = IPPROTO_SCTP;
case 'b':
show_ips = 1;
exit(EXIT_FAILURE);
}
break;
+ case 'L':
+ localport = atoi(optarg);
+ if (localport > 65535 || localport < MinPort) {
+ fprintf(stderr, "Illegal local port number.\n");
+ exit(EXIT_FAILURE);
+ }
+ break;
case 'Z':
tcp_timeout = atoi(optarg);
tcp_timeout *= 1000000;
"\t\t[-i INTERVAL] [-c COUNT] [-s PACKETSIZE] [-B BITPATTERN]\n"
"\t\t[-Q TOS] [--mpls]\n"
"\t\t[-a ADDRESS] [-f FIRST-TTL] [-m MAX-TTL]\n"
- "\t\t[--udp] [--tcp] [--sctp] [-P PORT] [-Z TIMEOUT]\n"
+ "\t\t[--udp] [--tcp] [--sctp] [-P PORT] [-L LOCALPORT] [-Z TIMEOUT]\n"
"\t\t[-M MARK] HOSTNAME\n", argv[0]);
printf("See the man page for details.\n");
exit(0);
}
+ if (mtrtype == IPPROTO_UDP && remoteport && !InterfaceAddress) {
+ fprintf(stderr, "mtr: -a ADDRESS required in udp mode (-u) with remote port set (-P).\n");
+ exit(EXIT_FAILURE);
+ }
+
time_t now = time(NULL);
if (!names) append_to_names (argv[0], "localhost"); // default: localhost.
}
}
+
lock(argv[0], stdout);
display_open();
dns_open();
extern int af; /* address family of remote target */
extern int mtrtype; /* type of query packet used */
extern int remoteport; /* target port for TCP tracing */
+extern int localport; /* source port for UDP tracing */
extern int tcp_timeout; /* timeout for TCP connections */
#ifdef SO_MARK
extern int mark; /* SO_MARK to set for ping packet*/
/* Prepend pseudoheader to the udp datagram and calculate checksum */
-int udp_checksum(void *pheader, void *udata, int psize, int dsize)
+int udp_checksum(void *pheader, void *udata, int psize, int dsize, int alt_checksum)
{
unsigned int tsize = psize + dsize;
char csumpacket[tsize];
memset(csumpacket, (unsigned char) abs(bitpattern), abs(tsize));
+ if (alt_checksum && dsize >= 2) {
+ csumpacket[psize] = csumpacket[psize + 1] = 0;
+ }
struct UDPv4PHeader *prepend = (struct UDPv4PHeader *) csumpacket;
struct UDPv4PHeader *udppheader = (struct UDPv4PHeader *) pheader;
struct ICMPHeader *icmp = NULL;
struct UDPHeader *udp = NULL;
struct UDPv4PHeader *udpp = NULL;
+ uint16 checksum_result;
uint16 mypid;
/*ok int packetsize = sizeof(struct IPHeader) + sizeof(struct ICMPHeader) + datasize;*/
if ( packetsize < MINPACKET ) packetsize = MINPACKET;
if ( packetsize > MAXPACKET ) packetsize = MAXPACKET;
+ if ( mtrtype == IPPROTO_UDP && remoteport && packetsize < (MINPACKET + 2)) {
+ packetsize = MINPACKET + 2;
+ }
memset(packet, (unsigned char) abs(bitpattern), abs(packetsize));
case IPPROTO_UDP:
udp = (struct UDPHeader *)(packet + iphsize);
udp->checksum = 0;
- mypid = (uint16)getpid();
- if (mypid < MinPort)
- mypid += MinPort;
-
+ if (!localport) {
+ mypid = (uint16)getpid();
+ if (mypid < MinPort)
+ mypid += MinPort;
+ } else {
+ mypid = (uint16)localport;
+ }
udp->srcport = htons(mypid);
udp->length = htons(abs(packetsize) - iphsize);
- udp->dstport = new_sequence(index);
- gettimeofday(&sequence[udp->dstport].time, NULL);
- udp->dstport = htons(udp->dstport);
+ if (!remoteport) {
+ udp->dstport = new_sequence(index);
+ gettimeofday(&sequence[udp->dstport].time, NULL);
+ udp->dstport = htons(udp->dstport);
+ } else {
+ // keep dstport constant, stuff sequence into the checksum
+ udp->dstport = htons(remoteport);
+ udp->checksum = new_sequence(index);
+ gettimeofday(&sequence[udp->checksum].time, NULL);
+ udp->checksum = htons(udp->checksum);
+ }
break;
}
switch ( mtrtype ) {
case IPPROTO_UDP:
/* checksum is not mandatory. only calculate if we know ip->saddr */
- if (ip->saddr) {
+ if (udp->checksum) {
udpp = (struct UDPv4PHeader *)(malloc(sizeof(struct UDPv4PHeader)));
udpp->saddr = ip->saddr;
udpp->daddr = ip->daddr;
udpp->protocol = ip->protocol;
udpp->len = udp->length;
- udp->checksum = udp_checksum(udpp, udp, sizeof(struct UDPv4PHeader), abs(packetsize) - iphsize);
+ checksum_result = udp_checksum(udpp, udp, sizeof(struct UDPv4PHeader), abs(packetsize) - iphsize, 1);
+ packet[iphsize + sizeof(struct UDPHeader)] = checksum_result & 0xff;
+ packet[iphsize + sizeof(struct UDPHeader) + 1] = checksum_result >> 8;
+ } else if (ip->saddr) {
+ udpp = (struct UDPv4PHeader *)(malloc(sizeof(struct UDPv4PHeader)));
+ udpp->saddr = ip->saddr;
+ udpp->daddr = ip->daddr;
+ udpp->protocol = ip->protocol;
+ udpp->len = udp->length;
+ udp->checksum = udp_checksum(udpp, udp, sizeof(struct UDPv4PHeader), abs(packetsize) - iphsize, 0);
}
break;
}
switch ( mtrtype ) {
case IPPROTO_UDP:
/* kernel checksum calculation */
+ if (udp->checksum) {
+ offset = sizeof(struct UDPHeader);
+ }
if ( setsockopt(sendsock, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, sizeof(offset)) ) {
perror( "setsockopt IPV6_CHECKSUM" );
exit( EXIT_FAILURE);
break;
#endif
}
- sequence = ntohs(udpheader->dstport);
+ if (remoteport && remoteport == ntohs(udpheader->dstport)) {
+ sequence = ntohs(udpheader->checksum);
+ } else if (!remoteport) {
+ sequence = ntohs(udpheader->dstport);
+ }
}
break;