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