3 * Report MTU on path to specified host
5 * (c) 2008 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of Trivial IP Encryption (TrIPE).
12 * TrIPE is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * TrIPE is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with TrIPE; if not, write to the Free Software Foundation,
24 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 /*----- Header files ------------------------------------------------------*/
37 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
46 #include <mLib/dstr.h>
48 #include <mLib/mdwopt.h>
49 #include <mLib/quis.h>
50 #include <mLib/report.h>
53 /*----- Static variables --------------------------------------------------*/
55 static unsigned char buf
[65536];
57 /*----- Utility functions -------------------------------------------------*/
59 /* Fill buffer with a constant but pseudorandom string. Uses a simple
62 static void fillbuffer(unsigned char *p
, size_t sz
)
64 unsigned int y
= 0xbc20;
65 const unsigned char *l
= p
+ sz
;
71 for (i
= 0; i
< 8; i
++) {
72 if (!(y
& 0x8000)) y
<<= 1;
73 else y
= (y
<< 1) ^ POLY
;
78 /*----- Doing the actual job ----------------------------------------------*/
83 # define IP_MTU 14 /* Blech! */
86 static int pathmtu(struct sockaddr_in
*sin
, double to
)
93 struct timeval tv
, tvproto
;
95 tvproto
.tv_sec
= to
; tvproto
.tv_usec
= (to
- tvproto
.tv_sec
) * 1000000;
96 if ((sk
= socket(PF_INET
, SOCK_DGRAM
, 0)) < 0) goto fail_0
;
98 if (setsockopt(sk
, SOL_IP
, IP_MTU_DISCOVER
, &i
, sizeof(i
)))
100 if (connect(sk
, (struct sockaddr
*)sin
, sizeof(*sin
))) goto fail_1
;
103 if (getsockopt(sk
, SOL_IP
, IP_MTU
, &mtu
, &sz
)) goto fail_1
;
104 if (write(sk
, buf
, mtu
- 28) < 0) goto fail_1
;
105 FD_SET(sk
, &fd_in
); tv
= tvproto
;
106 if (select(sk
+ 1, &fd_in
, 0, 0, &tv
) < 0) goto fail_1
;
107 if (!FD_ISSET(sk
, &fd_in
)) break;
108 if (read(sk
, &i
, 1) >= 0 ||
109 errno
== ECONNREFUSED
|| errno
== EHOSTUNREACH
)
111 if (errno
!= EMSGSIZE
) goto fail_1
;
124 # error "path MTU discovery not implemented"
128 /*----- Help options ------------------------------------------------------*/
130 static void version(FILE *fp
)
131 { pquis(fp
, "$, TrIPE version " VERSION
"\n"); }
133 static void usage(FILE *fp
)
134 { pquis(fp
, "Usage: $ [-t TIMEOUT] [-H HEADER] HOST [PORT]\n"); }
136 static void help(FILE *fp
)
145 -h, --help Show this help text.\n\
146 -v, --version Show version number.\n\
147 -u, --usage Show brief usage message.\n\
149 -t, --timeout=TIMEOUT Time to wait for reply, in seconds.\n\
150 -H, --header=HEX Packet header, in hexadecimal.\n\
154 /*----- Main code ---------------------------------------------------------*/
156 int main(int argc
, char *argv
[])
158 struct sockaddr_in sin
;
173 fillbuffer(buf
, sizeof(buf
));
174 sin
.sin_port
= htons(7);
177 static const struct option opts
[] = {
178 { "help", 0, 0, 'h' },
179 { "version", 0, 0, 'v' },
180 { "usage", 0, 0, 'u' },
181 { "header", OPTF_ARGREQ
, 0, 'H' },
182 { "timeout", OPTF_ARGREQ
, 0, 't' },
186 i
= mdwopt(argc
, argv
, "hvu" "H:", opts
, 0, 0, 0);
189 case 'h': help(stdout
); exit(0);
190 case 'v': version(stdout
); exit(0);
191 case 'u': usage(stdout
); exit(0);
196 hex_decode(&hc
, optarg
, strlen(optarg
), &d
);
197 hex_decode(&hc
, 0, 0, &d
);
198 sz
= d
.len
< sizeof(buf
) ? d
.len
: sizeof(buf
);
199 memcpy(buf
, d
.buf
, sz
);
204 to
= strtod(optarg
, &q
);
205 if (errno
|| *q
) die(EXIT_FAILURE
, "bad timeout");
213 argv
+= optind
; argc
-= optind
;
214 if ((f
& f_bogus
) || 1 > argc
|| argc
> 2) {
219 if ((h
= gethostbyname(*argv
)) == 0)
220 die(EXIT_FAILURE
, "unknown host `%s': %s", *argv
, hstrerror(h_errno
));
221 if (h
->h_addrtype
!= AF_INET
)
222 die(EXIT_FAILURE
, "unsupported address family for host `%s'", *argv
);
223 memcpy(&sin
.sin_addr
, h
->h_addr
, sizeof(struct in_addr
));
228 u
= strtoul(*argv
, &q
, 0);
230 sin
.sin_port
= htons(u
);
231 else if ((s
= getservbyname(*argv
, "udp")) == 0)
232 die(EXIT_FAILURE
, "unknown UDP service `%s'", *argv
);
234 sin
.sin_port
= s
->s_port
;
237 sin
.sin_family
= AF_INET
;
238 i
= pathmtu(&sin
, to
);
240 die(EXIT_FAILURE
, "failed to discover MTU: %s", strerror(errno
));
242 if (ferror(stdout
) || fflush(stdout
) || fclose(stdout
))
243 die(EXIT_FAILURE
, "failed to write result: %s", strerror(errno
));
247 /*----- That's all, folks -------------------------------------------------*/