1 #include "findmtu.h"
2
3 /**
4 * Set up ICMPv6 error reception
5 * Input: sending socket fd
6 */
recv_init(int sendfd)7 int recv_init(int sendfd) {
8 int on;
9
10 on = IPV6_PMTUDISC_DO;
11 if (setsockopt(sendfd, SOL_IPV6, IPV6_MTU_DISCOVER, &on, sizeof(on))) {
12 perror("sockopt IPV6_MTU_DISCOVER");
13 exit(1);
14 }
15
16 on = 1;
17 if (setsockopt(sendfd, SOL_IPV6, IPV6_RECVERR, &on, sizeof(on))) {
18 perror("sockopt IPV6_RECVERR");
19 exit(1);
20 }
21
22 return sendfd;
23 }
24
25 /**
26 * Wait for reply to a probe packet
27 * Input: socket fd
28 * Output: 0 for timeout, 1 if a reply arrives
29 */
wait_for_reply(int fd,struct icmpv6responsefilter * filter)30 int wait_for_reply(int fd, struct icmpv6responsefilter *filter) {
31 fd_set fds;
32 struct timeval tv;
33 FD_ZERO(&fds);
34 FD_SET(fd, &fds);
35 tv.tv_sec = 2;
36 tv.tv_usec = 0;
37 return select(fd+1, &fds, NULL, NULL, &tv);
38 }
39
40 /**
41 * Process ICMPv6 messages from a socket
42 * Input: socket fd
43 * Output: struct mtureply with address of reporting host, MTU, and ICMP type/code
44 */
45
recvmtu(int fd)46 struct mtureply recvmtu(int fd) {
47 struct msghdr msg;
48 struct iovec iov;
49 struct probehdr rcvbuf;
50 struct sock_extended_err *e;
51 struct cmsghdr *cmsg;
52 char cbuf[512];
53 struct mtureply reply;
54
55 time(&rcvbuf.tv.tv_sec);
56
57 iov.iov_base = &rcvbuf;
58 iov.iov_len = sizeof(rcvbuf);
59
60 msg.msg_name = NULL;
61 msg.msg_namelen = 0;
62 msg.msg_iov = &iov;
63 msg.msg_iovlen = 1;
64 msg.msg_flags = 0;
65 msg.msg_control = cbuf;
66 msg.msg_controllen = sizeof(cbuf);
67
68 memset(reply.addr, 0, sizeof(reply.addr));
69 reply.mtu = 0;
70 reply.ee_type = reply.ee_code = 0;
71
72 if(recvmsg(fd, &msg, MSG_ERRQUEUE) < 0)
73 return reply;
74
75 for(cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
76 if (cmsg->cmsg_level == SOL_IPV6)
77 if (cmsg->cmsg_type == IPV6_RECVERR)
78 e = (struct sock_extended_err *)CMSG_DATA(cmsg);
79
80 if(e->ee_origin == SO_EE_ORIGIN_ICMP6) {
81 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)(e+1);
82 inet_ntop(AF_INET6, &sin6->sin6_addr, reply.addr, sizeof(reply.addr));
83 }
84
85 switch(e->ee_errno) {
86 case EMSGSIZE:
87 reply.mtu = e->ee_info;
88 break;
89 case ECONNREFUSED: /* Target reached */
90 reply.mtu = -1;
91 break;
92 default: /* Other error. Set it and bail */
93 reply.mtu = -1;
94 reply.ee_type = e->ee_type;
95 reply.ee_code = e->ee_code;
96 break;
97 }
98
99 return(reply);
100 }
101
getfilter(int fd)102 struct icmpv6responsefilter *getfilter(int fd) {
103 return NULL;
104 }
105