summaryrefslogtreecommitdiffstats
path: root/usr.sbin/traceroute6/traceroute6.c
diff options
context:
space:
mode:
authordwmalone <dwmalone@FreeBSD.org>2008-02-10 21:06:38 +0000
committerdwmalone <dwmalone@FreeBSD.org>2008-02-10 21:06:38 +0000
commitdca3074678fb1339515c7936447df93d7a793e38 (patch)
treeed66fedaf33c8b2e3907ed11bf3b5c31e73d4c81 /usr.sbin/traceroute6/traceroute6.c
parent22b65bed611e9f6a413422361d1b25f1c5c7792a (diff)
downloadFreeBSD-src-dca3074678fb1339515c7936447df93d7a793e38.zip
FreeBSD-src-dca3074678fb1339515c7936447df93d7a793e38.tar.gz
Give traceroute6 the ability to traceroute with packets with no
upper layer header (IP PROTO = 59). Useful for testing firewalls. MFC after: 2 months
Diffstat (limited to 'usr.sbin/traceroute6/traceroute6.c')
-rw-r--r--usr.sbin/traceroute6/traceroute6.c151
1 files changed, 104 insertions, 47 deletions
diff --git a/usr.sbin/traceroute6/traceroute6.c b/usr.sbin/traceroute6/traceroute6.c
index 617e5a5..d06502f 100644
--- a/usr.sbin/traceroute6/traceroute6.c
+++ b/usr.sbin/traceroute6/traceroute6.c
@@ -317,7 +317,7 @@ int setpolicy(int so, char *policy);
#endif
#endif
void send_probe(int, u_long);
-struct udphdr *get_udphdr(struct ip6_hdr *, u_char *);
+void *get_uphdr(struct ip6_hdr *, u_char *);
int get_hoplim(struct msghdr *);
double deltaT(struct timeval *, struct timeval *);
char *pr_type(int);
@@ -357,7 +357,7 @@ int options; /* socket options */
int verbose;
int waittime = 5; /* time to wait for response (in seconds) */
int nflag; /* print addresses numerically */
-int useicmp;
+int useproto = IPPROTO_UDP; /* protocol to use to send packet */
int lflag; /* print both numerical address & hostname */
int
@@ -383,13 +383,6 @@ main(argc, argv)
exit(5);
}
- /* revoke privs */
- uid = getuid();
- if (setresuid(uid, uid, uid) == -1) {
- perror("setresuid");
- exit(1);
- }
-
size = sizeof(i);
(void) sysctl(mib, sizeof(mib)/sizeof(mib[0]), &i, &size, NULL, 0);
max_hops = i;
@@ -418,7 +411,7 @@ main(argc, argv)
seq = 0;
- while ((ch = getopt(argc, argv, "df:g:Ilm:np:q:rs:w:v")) != -1)
+ while ((ch = getopt(argc, argv, "df:g:Ilm:nNp:q:rs:Uvw:")) != -1)
switch (ch) {
case 'd':
options |= SO_DEBUG;
@@ -470,7 +463,7 @@ main(argc, argv)
freehostent(hp);
break;
case 'I':
- useicmp++;
+ useproto = IPPROTO_ICMPV6;
ident = htons(getpid() & 0xffff); /* same as ping6 */
break;
case 'l':
@@ -489,6 +482,9 @@ main(argc, argv)
case 'n':
nflag++;
break;
+ case 'N':
+ useproto = IPPROTO_NONE;
+ break;
case 'p':
ep = NULL;
errno = 0;
@@ -532,6 +528,9 @@ main(argc, argv)
case 'v':
verbose++;
break;
+ case 'U':
+ useproto = IPPROTO_UDP;
+ break;
case 'w':
ep = NULL;
errno = 0;
@@ -553,12 +552,44 @@ main(argc, argv)
argc -= optind;
argv += optind;
+ /*
+ * Open socket to send probe packets.
+ */
+ switch (useproto) {
+ case IPPROTO_ICMPV6:
+ sndsock = rcvsock;
+ break;
+ case IPPROTO_UDP:
+ if ((sndsock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("socket(SOCK_DGRAM)");
+ exit(5);
+ }
+ break;
+ case IPPROTO_NONE:
+ if ((sndsock = socket(AF_INET6, SOCK_RAW, IPPROTO_NONE)) < 0) {
+ perror("socket(SOCK_RAW)");
+ exit(5);
+ }
+ break;
+ default:
+ fprintf(stderr, "traceroute6: unknown probe protocol %d",
+ useproto);
+ exit(5);
+ }
if (max_hops < first_hop) {
fprintf(stderr,
"traceroute6: max hoplimit must be larger than first hoplimit.\n");
exit(1);
}
+ /* revoke privs */
+ uid = getuid();
+ if (setresuid(uid, uid, uid) == -1) {
+ perror("setresuid");
+ exit(1);
+ }
+
+
if (argc < 1 || argc > 2)
usage();
@@ -608,10 +639,22 @@ main(argc, argv)
exit(1);
}
}
- if (useicmp)
+ switch (useproto) {
+ case IPPROTO_ICMPV6:
minlen = ICMP6ECHOLEN + sizeof(struct tv32);
- else
+ break;
+ case IPPROTO_UDP:
minlen = sizeof(struct opacket);
+ break;
+ case IPPROTO_NONE:
+ minlen = 0;
+ datalen = 0;
+ break;
+ default:
+ fprintf(stderr, "traceroute6: unknown probe protocol %d.\n",
+ useproto);
+ exit(1);
+ }
if (datalen < minlen)
datalen = minlen;
else if (datalen >= MAXPACKET) {
@@ -682,21 +725,10 @@ main(argc, argv)
#endif /*IPSEC_POLICY_IPSEC*/
#endif /*IPSEC*/
- /*
- * Send UDP or ICMP
- */
- if (useicmp) {
- sndsock = rcvsock;
- } else {
- if ((sndsock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
- perror("socket(SOCK_DGRAM)");
- exit(5);
- }
- }
#ifdef SO_SNDBUF
i = datalen;
if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&i,
- sizeof(i)) < 0) {
+ sizeof(i)) < 0 && useproto != IPPROTO_NONE) {
perror("setsockopt(SO_SNDBUF)");
exit(6);
}
@@ -986,6 +1018,8 @@ send_probe(seq, hops)
int seq;
u_long hops;
{
+ struct icmp6_hdr *icp;
+ struct opacket *op;
struct timeval tv;
struct tv32 tv32;
int i;
@@ -1001,8 +1035,9 @@ send_probe(seq, hops)
tv32.tv32_sec = htonl(tv.tv_sec);
tv32.tv32_usec = htonl(tv.tv_usec);
- if (useicmp) {
- struct icmp6_hdr *icp = (struct icmp6_hdr *)outpacket;
+ switch (useproto) {
+ case IPPROTO_ICMPV6:
+ icp = (struct icmp6_hdr *)outpacket;
icp->icmp6_type = ICMP6_ECHO_REQUEST;
icp->icmp6_code = 0;
@@ -1011,12 +1046,20 @@ send_probe(seq, hops)
icp->icmp6_seq = htons(seq);
bcopy(&tv32, ((u_int8_t *)outpacket + ICMP6ECHOLEN),
sizeof(tv32));
- } else {
- struct opacket *op = outpacket;
+ break;
+ case IPPROTO_UDP:
+ op = outpacket;
op->seq = seq;
op->hops = hops;
bcopy(&tv32, &op->tv, sizeof tv32);
+ break;
+ case IPPROTO_NONE:
+ /* No space for anything. No harm as seq/tv32 are decorative. */
+ break;
+ default:
+ fprintf(stderr, "Unknown probe protocol %d.\n", useproto);
+ exit(1);
}
i = sendto(sndsock, (char *)outpacket, datalen, 0,
@@ -1196,23 +1239,34 @@ packet_ok(mhdr, cc, seq)
if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT)
|| type == ICMP6_DST_UNREACH) {
struct ip6_hdr *hip;
- struct udphdr *up;
+ void *up;
hip = (struct ip6_hdr *)(icp + 1);
- if ((up = get_udphdr(hip, (u_char *)(buf + cc))) == NULL) {
+ if ((up = get_uphdr(hip, (u_char *)(buf + cc))) == NULL) {
if (verbose)
warnx("failed to get upper layer header");
return(0);
}
- if (useicmp &&
- ((struct icmp6_hdr *)up)->icmp6_id == ident &&
- ((struct icmp6_hdr *)up)->icmp6_seq == htons(seq))
- return (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1);
- else if (!useicmp &&
- up->uh_sport == htons(srcport) &&
- up->uh_dport == htons(port + seq))
- return (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1);
- } else if (useicmp && type == ICMP6_ECHO_REPLY) {
+ switch (useproto) {
+ case IPPROTO_ICMPV6:
+ if (((struct icmp6_hdr *)up)->icmp6_id == ident &&
+ ((struct icmp6_hdr *)up)->icmp6_seq == htons(seq))
+ return (type == ICMP6_TIME_EXCEEDED ?
+ -1 : code + 1);
+ break;
+ case IPPROTO_UDP:
+ if (((struct udphdr *)up)->uh_sport == htons(srcport) &&
+ ((struct udphdr *)up)->uh_dport == htons(port + seq))
+ return (type == ICMP6_TIME_EXCEEDED ?
+ -1 : code + 1);
+ break;
+ case IPPROTO_NONE:
+ return (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1);
+ default:
+ fprintf(stderr, "Unknown probe proto %d.\n", useproto);
+ break;
+ }
+ } else if (useproto == IPPROTO_ICMPV6 && type == ICMP6_ECHO_REPLY) {
if (icp->icmp6_id == ident &&
icp->icmp6_seq == htons(seq))
return (ICMP6_DST_UNREACH_NOPORT + 1);
@@ -1250,29 +1304,32 @@ packet_ok(mhdr, cc, seq)
/*
* Increment pointer until find the UDP or ICMP header.
*/
-struct udphdr *
-get_udphdr(ip6, lim)
+void *
+get_uphdr(ip6, lim)
struct ip6_hdr *ip6;
u_char *lim;
{
u_char *cp = (u_char *)ip6, nh;
int hlen;
+ static u_char none_hdr[1]; /* Fake pointer for IPPROTO_NONE. */
- if (cp + sizeof(*ip6) >= lim)
+ if (cp + sizeof(*ip6) > lim)
return(NULL);
nh = ip6->ip6_nxt;
cp += sizeof(struct ip6_hdr);
- while (lim - cp >= 8) {
+ while (lim - cp >= (nh == IPPROTO_NONE ? 0 : 8)) {
switch (nh) {
case IPPROTO_ESP:
case IPPROTO_TCP:
return(NULL);
case IPPROTO_ICMPV6:
- return(useicmp ? (struct udphdr *)cp : NULL);
+ return(useproto == nh ? cp : NULL);
case IPPROTO_UDP:
- return(useicmp ? NULL : (struct udphdr *)cp);
+ return(useproto == nh ? cp : NULL);
+ case IPPROTO_NONE:
+ return(useproto == nh ? none_hdr : NULL);
case IPPROTO_FRAGMENT:
hlen = sizeof(struct ip6_frag);
nh = ((struct ip6_frag *)cp)->ip6f_nxt;
@@ -1369,7 +1426,7 @@ usage()
{
fprintf(stderr,
-"usage: traceroute6 [-dIlnrv] [-f firsthop] [-g gateway] [-m hoplimit]\n"
+"usage: traceroute6 [-dIlnNrUv] [-f firsthop] [-g gateway] [-m hoplimit]\n"
" [-p port] [-q probes] [-s src] [-w waittime] target [datalen]\n");
exit(1);
}
OpenPOWER on IntegriCloud