#include "findmtu.h" /** * Set up ICMPv6 error reception * Input: sending socket fd */ int recv_init(int sendfd) { int on; on = IPV6_PMTUDISC_DO; if (setsockopt(sendfd, SOL_IPV6, IPV6_MTU_DISCOVER, &on, sizeof(on))) { perror("sockopt IPV6_MTU_DISCOVER"); exit(1); } on = 1; if (setsockopt(sendfd, SOL_IPV6, IPV6_RECVERR, &on, sizeof(on))) { perror("sockopt IPV6_RECVERR"); exit(1); } return sendfd; } /** * Wait for reply to a probe packet * Input: socket fd * Output: 0 for timeout, 1 if a reply arrives */ int wait_for_reply(int fd, struct icmpv6responsefilter *filter) { fd_set fds; struct timeval tv; FD_ZERO(&fds); FD_SET(fd, &fds); tv.tv_sec = 2; tv.tv_usec = 0; return select(fd+1, &fds, NULL, NULL, &tv); } /** * Process ICMPv6 messages from a socket * Input: socket fd * Output: struct mtureply with address of reporting host, MTU, and ICMP type/code */ struct mtureply recvmtu(int fd) { struct msghdr msg; struct iovec iov; struct probehdr rcvbuf; struct sock_extended_err *e; struct cmsghdr *cmsg; char cbuf[512]; struct mtureply reply; time(&rcvbuf.tv.tv_sec); iov.iov_base = &rcvbuf; iov.iov_len = sizeof(rcvbuf); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_flags = 0; msg.msg_control = cbuf; msg.msg_controllen = sizeof(cbuf); memset(reply.addr, 0, sizeof(reply.addr)); reply.mtu = 0; reply.ee_type = reply.ee_code = 0; if(recvmsg(fd, &msg, MSG_ERRQUEUE) < 0) return reply; for(cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) if (cmsg->cmsg_level == SOL_IPV6) if (cmsg->cmsg_type == IPV6_RECVERR) e = (struct sock_extended_err *)CMSG_DATA(cmsg); if(e->ee_origin == SO_EE_ORIGIN_ICMP6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)(e+1); inet_ntop(AF_INET6, &sin6->sin6_addr, reply.addr, sizeof(reply.addr)); } switch(e->ee_errno) { case EMSGSIZE: reply.mtu = e->ee_info; break; case ECONNREFUSED: /* Target reached */ reply.mtu = -1; break; default: /* Other error. Set it and bail */ reply.mtu = -1; reply.ee_type = e->ee_type; reply.ee_code = e->ee_code; break; } return(reply); } struct icmpv6responsefilter *getfilter(int fd) { return NULL; }