Ejemplo n.º 1
0
PRIVATE_EXTERN int
RTADVSocketSendSolicitation(RTADVSocketRef sock, bool lladdr_ok)
{
    interface_t *	if_p = RTADVSocketGetInterface(sock);
    boolean_t		needs_close = FALSE;
    int			ret;
    uint32_t		txbuf[RTSOL_PACKET_MAX / sizeof(uint32_t)];
    int			txbuf_used;	/* amount actually used */


    if (sock->fd_open == FALSE) {
	/* open the RTADV socket in case it's needed */
	if (RTADVSocketOpenSocket(sock) == FALSE) {
	    my_log(LOG_NOTICE, "RTADVSocket: failed to open socket");
	    return (FALSE);
	}
	needs_close = TRUE;
    }
    txbuf_used = RTADVSocketInitTXBuf(sock, txbuf, lladdr_ok);
    ret = IPv6SocketSend(FDCalloutGetFD(S_globals->read_fd),
			 if_link_index(if_p),
			 &sin6_allrouters,
			 (void *)txbuf, txbuf_used,
			 ND_RTADV_HOP_LIMIT);
    if (needs_close) {
	RTADVSocketCloseSocket(sock);
    }
    return (ret);
}
int
DHCPv6SocketTransmit(DHCPv6SocketRef sock,
		     DHCPv6PacketRef pkt, int pkt_len)
{
    DHCPv6OptionErrorString	err;
    int				ret;
    boolean_t			needs_close = FALSE;

    if (sock->fd_open == FALSE) {
	/* open the DHCPv6 socket in case it's needed */
	if (DHCPv6SocketOpenSocket(sock) == FALSE) {
	    my_log(LOG_ERR, "DHCPv6Socket: failed to open socket");
	    return (FALSE);
	}
	needs_close = TRUE;
    }
    if (S_verbose) {
	DHCPv6OptionListRef	options;
	CFMutableStringRef	str;
	
	str = CFStringCreateMutable(NULL, 0);
	DHCPv6PacketPrintToString(str, pkt, pkt_len);
	options = DHCPv6OptionListCreateWithPacket(pkt, pkt_len, &err);
	if (options == NULL) {
	    my_log_fl(LOG_DEBUG, "parse options failed, %s",
		      err.str);
	}
	else {
	    DHCPv6OptionListPrintToString(str, options);
	    DHCPv6OptionListRelease(&options);
	}
	my_log(-LOG_DEBUG,"[%s] Transmit %@", if_name(sock->if_p), str);
	CFRelease(str);
    }
    ret = S_send_packet(FDCalloutGetFD(S_globals->read_fd),
			if_link_index(sock->if_p), pkt, pkt_len);
    if (needs_close) {
	DHCPv6SocketCloseSocket(sock);
    }
    return (ret);
}
static void
DHCPv6SocketDelayedClose(void * arg1, void * arg2, void * arg3)
{
    if (S_globals->read_fd == NULL) {
	my_log(LOG_ERR, 
	       "DHCPv6SocketDelayedClose(): socket is already closed");
	return;
    }
    if (S_globals->read_fd_refcount > 0) {
	my_log(LOG_ERR, 
	       "DHCPv6SocketDelayedClose(): called when socket in use");
	return;
    }
    my_log(LOG_DEBUG,
	   "DHCPv6SocketDelayedClose(): closing DHCPv6 socket %d",
	   FDCalloutGetFD(S_globals->read_fd));

    /* this closes the file descriptor */
    FDCalloutRelease(&S_globals->read_fd);
    return;
}
Ejemplo n.º 4
0
STATIC void
RTADVSocketDelayedClose(void * arg1, void * arg2, void * arg3)
{
    if (S_globals->read_fd == NULL) {
	my_log(LOG_NOTICE,
	       "RTADVSocketDelayedClose(): socket is already closed");
	return;
    }
    if (S_globals->read_fd_refcount > 0) {
	my_log(LOG_NOTICE,
	       "RTADVSocketDelayedClose(): called when socket in use");
	return;
    }
    my_log(LOG_INFO,
	   "RTADVSocketDelayedClose(): closing RTADV socket %d",
	   FDCalloutGetFD(S_globals->read_fd));

    /* this closes the file descriptor */
    FDCalloutRelease(&S_globals->read_fd);
    return;
}
static void
DHCPv6SocketRead(void * arg1, void * arg2)
{
    struct cmsghdr *	cm;
    char		cmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
    struct iovec 	iov;
    struct sockaddr_in6 from;
    struct msghdr 	mhdr;
    int			n;
    struct in6_pktinfo *pktinfo = NULL;
    char	 	receive_buf[1500];

    /* initialize msghdr for receiving packets */
    iov.iov_base = (caddr_t)receive_buf;
    iov.iov_len = sizeof(receive_buf);
    mhdr.msg_name = (caddr_t)&from;
    mhdr.msg_namelen = sizeof(from);
    mhdr.msg_iov = &iov;
    mhdr.msg_iovlen = 1;
    mhdr.msg_control = (caddr_t)cmsgbuf;
    mhdr.msg_controllen = sizeof(cmsgbuf);

    /* get message */
    n = recvmsg(FDCalloutGetFD(S_globals->read_fd), &mhdr, 0);
    if (n < 0) {
	if (errno != EAGAIN) {
	    my_log(LOG_ERR, "DHCPv6SocketRead: recvfrom failed %s (%d)",
		   strerror(errno), errno);
	}
	return;
    }
    if (n == 0) {
	/* nothing to read */
	return;
    }

    /* get the control message that has the interface index */
    pktinfo = NULL;
    for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&mhdr);
	 cm != NULL;
	 cm = (struct cmsghdr *)CMSG_NXTHDR(&mhdr, cm)) {
	if (cm->cmsg_level != IPPROTO_IPV6) {
	    continue;
	}
	switch (cm->cmsg_type) {
	case IPV6_PKTINFO:
	    if (cm->cmsg_len < CMSG_LEN(sizeof(struct in6_pktinfo))) {
		continue;
	    }
	    /* ALIGN: CMSG_DATA is should return aligned data */ 
	    pktinfo = (struct in6_pktinfo *)(void *)(CMSG_DATA(cm));
	    break;
	default:
	    /* this should never occur */
	    my_log(LOG_ERR, "Why did we get control message type %d?",
		   cm->cmsg_type);
	    break;
	}
    }
    if (pktinfo == NULL) {
	my_log(LOG_ERR, 
	       "DHCPv6SocketRead: missing IPV6_PKTINFO");
	return;
    }
    DHCPv6SocketDemux(pktinfo->ipi6_ifindex, 
		      (const DHCPv6PacketRef)receive_buf, n);
    return;
}
Ejemplo n.º 6
0
STATIC void
RTADVSocketRead(void * arg1, void * arg2)
{
    struct cmsghdr *			cm;
    char				cmsgbuf[RECEIVE_CMSG_BUF_SIZE];
    int *				hop_limit_p;
    struct icmp6_hdr *			icmp_hdr;
    struct iovec 			iov;
    struct sockaddr_in6 		from;
    struct msghdr 			mhdr;
    ssize_t				n;
    struct nd_router_advert * 		ndra_p;
    char 				ntopbuf[INET6_ADDRSTRLEN];
    struct in6_pktinfo *		pktinfo = NULL;
    char	 			receive_buf[1500];

    /* initialize msghdr for receiving packets */
    iov.iov_base = (caddr_t)receive_buf;
    iov.iov_len = sizeof(receive_buf);
    mhdr.msg_name = (caddr_t)&from;
    mhdr.msg_namelen = sizeof(from);
    mhdr.msg_iov = &iov;
    mhdr.msg_iovlen = 1;
    mhdr.msg_control = (caddr_t)cmsgbuf;
    mhdr.msg_controllen = sizeof(cmsgbuf);

    /* get message */
    n = recvmsg(FDCalloutGetFD(S_globals->read_fd), &mhdr, 0);
    if (n < 0) {
	if (errno != EAGAIN) {
	    my_log(LOG_ERR, "RTADVSocketRead: recvfrom failed %s (%d)",
		   strerror(errno), errno);
	}
	return;
    }
    if (n == 0) {
	/* nothing to read */
	return;
    }
    if (n < sizeof(struct nd_router_advert)) {
	my_log(LOG_NOTICE, "RTADVSocketRead: packet size(%d) is too short", n);
	return;
    }
    if (!IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) {
	my_log(LOG_NOTICE,
	       "RTADVSocketRead: RA has non link-local source address %s",
	       inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, sizeof(ntopbuf)));
	return;
    }

    /* process the packet */
    pktinfo = NULL;
    hop_limit_p = NULL;
    for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&mhdr);
	 cm != NULL;
	 cm = (struct cmsghdr *)CMSG_NXTHDR(&mhdr, cm)) {
	if (cm->cmsg_level != IPPROTO_IPV6) {
	    continue;
	}
	switch (cm->cmsg_type) {
	case IPV6_PKTINFO:
	    if (cm->cmsg_len < CMSG_LEN(sizeof(struct in6_pktinfo))) {
		continue;
	    }
	    /* ALIGN: CMSG_DATA returns aligned data, cast ok. */
	    pktinfo = (struct in6_pktinfo *)(void *)(CMSG_DATA(cm));
	    break;
	case IPV6_HOPLIMIT:
	    if (cm->cmsg_len < CMSG_LEN(sizeof(int))) {
		continue;
	    }
	    /* ALIGN: CMSG_DATA returns aligned data, cast ok. */
	    hop_limit_p = (int *)(void *)CMSG_DATA(cm);
	    break;
	default:
	    /* this should never occur */
	    my_log(LOG_NOTICE, "RTADVSocketRead: why control message type %d?",
		   cm->cmsg_type);
	    break;
	}
    }
    if (pktinfo == NULL) {
	my_log(LOG_NOTICE,
	       "RTADVSocketRead: missing IPV6_PKTINFO");
	return;
    }
    if (hop_limit_p == NULL) {
	my_log(LOG_NOTICE, "RTADVSocketRead: missing IPV6_HOPLIMIT");
	return;
    }
    ndra_p = (struct nd_router_advert *)receive_buf;
    icmp_hdr = &ndra_p->nd_ra_hdr;
    if (icmp_hdr->icmp6_type != ND_ROUTER_ADVERT) {
	/* this should not happen, the kernel filters for us */
	my_log(LOG_NOTICE, "RTADVSocket: received unexpected ND packet type %d",
	       icmp_hdr->icmp6_type);
	return;
    }
    if (icmp_hdr->icmp6_code != 0) {
	my_log(LOG_NOTICE, "RTADVSocket: invalid icmp code %d",
	       icmp_hdr->icmp6_code);
	return;
    }
    if (ndra_p->nd_ra_router_lifetime == 0) {
	/* router lifetime is zero, ignore it */
	return;
    }
    if (*hop_limit_p != ND_RTADV_HOP_LIMIT) {
	my_log(LOG_NOTICE, "RTADVSocket: invalid RA hop limit %d from %s",
	       *hop_limit_p, 
	       inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, sizeof(ntopbuf)));
	return;
    }
    RTADVSocketDemux(pktinfo->ipi6_ifindex, &from.sin6_addr, ndra_p, (int)n);
    return;
}