⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dhcp6relay.c

📁 DHCPv6协议在Linux操作系统下的一个客户端实现。
💻 C
📖 第 1 页 / 共 2 页
字号:
	}	ssock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);	if (ssock < 0) {		err(1, "socket(outsock)");		/* NOTREACHED */	}	if (ssock > maxfd)		maxfd = ssock;	if (setsockopt(ssock, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0) {		err(1, "setsockopt(ssock, SO_REUSEPORT)");		/* NOTREACHED */	}	if (setsockopt(ssock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {		err(1, "setsockopt(ssock, IPV6_V6ONLY)");		/* NOTREACHED */	}	if (bind(ssock, res->ai_addr, res->ai_addrlen) < 0) {		err(1, "bind(ssock)");		/* NOTREACHED */	}	memcpy(&sa6_client, res->ai_addr, sizeof(sa6_client));	freeaddrinfo(res);	if (setsockopt(ssock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mhops,		       sizeof(mhops)) < 0) {		err(1, "setsockopt(ssock, IPV6_MULTICAST_HOPS(%d))", mhops);		/* NOTREACHED */	}#ifdef IPV6_RECVPKTINFO	if (setsockopt(ssock, IPPROTO_IPV6, IPV6_RECVPKTINFO,		       &on, sizeof(on)) < 0) {		err(1, "setsockopt(IPV6_RECVPKTINFO)");		/* NOTREACHED */	}#else	if (setsockopt(ssock, IPPROTO_IPV6, IPV6_PKTINFO,		       &on, sizeof(on)) < 0) {		err(1, "setsockopt(IPV6_PKTINFO)");		/* NOTREACHED */	}#endif	/*	 * Setup a socket to receive ICMPv6 errors.	 */	if ((icmp6sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {		err(1, "socket(ICMPV6)");		/* NOTREACHED */	}	if (icmp6sock > maxfd) maxfd = icmp6sock;	/* set filter to receive error messages only */	ICMP6_FILTER_SETBLOCKALL(&filt);	for (type = 0; type < 128; type++)		ICMP6_FILTER_SETPASS(type, &filt);	if (setsockopt(icmp6sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,		       sizeof(filt)) < 0)		err(1, "setsockopt(ICMP6_FILTER)");}static voidrelay6_loop(){	fd_set readfds;	char rdev[IF_NAMESIZE];	int e, cc;	while(1) {		/* we'd rather use FD_COPY here, but it's not POSIX friendly */		FD_ZERO(&readfds);		FD_SET(csock, &readfds);		FD_SET(ssock, &readfds);		FD_SET(icmp6sock, &readfds);		e = select(maxfd + 1, &readfds, NULL, NULL, NULL);		switch(e) {		case 0:		/* impossible in our situation */			errx(1, "select returned 0");				/* NOTREACHED */		case -1:			err(1, "select");				/* NOTREACHED */		default:			break;		}		if (FD_ISSET(csock, &readfds) &&		    (cc = relay6_recv(csock, rdev)) > 0)			relay6_react(cc, rdatabuf, rdev, 1);		if (FD_ISSET(ssock, &readfds) &&		    (cc = relay6_recv(ssock, rdev)) > 0)			relay6_react(cc, rdatabuf, rdev, 0);		if (FD_ISSET(icmp6sock, &readfds) &&		    (cc = relay6_recv(icmp6sock, NULL)) > 0) {#ifdef notyet			icmp6_react();#endif 		}	}}static intrelay6_recv(s, rdevice)	int s;	char *rdevice;{	ssize_t len;	struct sockaddr_storage from;	struct in6_pktinfo *pi = NULL;	struct cmsghdr *cm;	rmh.msg_control = (caddr_t)rmsgctlbuf;	rmh.msg_controllen = rmsgctllen;	rmh.msg_name = (caddr_t)&from;	rmh.msg_namelen = sizeof(from);	if ((len = recvmsg(s, &rmh, 0)) < 0) {		dprintf(LOG_WARNING, "recvmsg: %s", strerror(errno));		return (-1);	/* should assert? */	}	dprintf(LOG_DEBUG, "relay6_recv: from %s, size %d",		addr2str((struct sockaddr *)&from), len); 	/* get optional information as ancillary data (if available) */	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rmh); cm;	     cm = (struct cmsghdr *)CMSG_NXTHDR(&rmh, cm)) {		if (cm->cmsg_level != IPPROTO_IPV6)			continue;		switch(cm->cmsg_type) {		case IPV6_PKTINFO:			pi = (struct in6_pktinfo *)CMSG_DATA(cm);			break;		}	}	if (rdevice) {		if (pi == NULL) {			dprintf(LOG_WARNING, "relay6_recv: "				"failed to get the arrival interface");			return (-1);		}		if (if_indextoname(pi->ipi6_ifindex, rdevice) == NULL) {			dprintf(LOG_WARNING, "if_indextoname(id = %d): %s",				pi->ipi6_ifindex, strerror(errno));			return (-1);		}	}	return (len);}static voidrelay6_react(siz, buf, dev, fromclient)	size_t siz;	int fromclient;	char *buf, *dev;{	union dhcp6 *dh6;	if (siz < 1) {		/* we need at least 1 byte to check type */		dprintf(LOG_DEBUG, "relay6_react: short packet");		return;	}		dh6 = (union dhcp6 *)buf;	dprintf(LOG_DEBUG, "relay6_react: msgtype=%d", dh6->dh6_msgtype);	if (fromclient) {		switch (dh6->dh6_msgtype) {		case DH6_SOLICIT:			relay6_react_solicit(buf, siz, dev);			break;		case DH6_REQUEST:#ifdef notyet			relay6_react_request(buf, siz, dev);#endif 			break;		default:			fprintf(stderr, "invalid msgtype (%d) from client",				dh6->dh6_msgtype);			break;		}	}	else {		switch (dh6->dh6_msgtype) {		case DH6_ADVERT:			relay6_react_advert(buf, siz, dev);			break;		case DH6_REPLY:#ifdef notyet			relay6_react_reply(buf, siz, dev);#endif			break;		default:			fprintf(stderr, "invalid msgtype (%d) from server",				dh6->dh6_msgtype);			break;		}	}}	static voidrelay6_react_solicit(buf, siz, dev)	char *buf, *dev;	size_t siz;{	struct dhcp6_solicit *dh6s;	struct prefix_list *p;	static struct iovec iov[2];	struct in6_addr myaddr;	int plen;	u_char *cp_plen;	dprintf(LOG_DEBUG, "relay6_react_solicit");	if (siz < sizeof(*dh6s)) {		dprintf(LOG_INFO,			"relay6_react_solicit: short packet (size = %d)", siz);		return;	}	dh6s = (struct dhcp6_solicit *)buf;	if (!IN6_IS_ADDR_LINKLOCAL(&dh6s->dh6sol_cliaddr)) {		dprintf(LOG_INFO,			"relay6_react_solicit: client address (%s) is not "			"link-local", in6addr2str(&dh6s->dh6sol_cliaddr, 0));		return;	}	/*	 * When sending a DHCP Solicit message, a client MUST set the Relay	 * Address field to 16 octets of zeros, and zero the prefix-size	 * field.	 * But we just warn if the client did not conformed to these rules.	 */	if (!IN6_IS_ADDR_UNSPECIFIED(&dh6s->dh6sol_relayaddr)) {		dprintf(LOG_INFO,			"relay6_react_solicit: relay address (%s) is not "			"the Unspecified address (ignored)",			in6addr2str(&dh6s->dh6sol_relayaddr, 0));	}	/* find a non-link-local address and fill in the relay address field */	memset(&myaddr, 0, sizeof(myaddr));	for (p = TAILQ_FIRST(&global_prefixes); p; p = TAILQ_NEXT(p, plink)) {		if (getifaddr(&myaddr, dev, &p->paddr.sin6_addr,			      p->plen, 0, IN6_IFF_INVALID) == 0) /* found */			break;	}	if (IN6_IS_ADDR_UNSPECIFIED(&myaddr)) {		dprintf(LOG_WARNING,			"relay6_react_solicit: can't find a non-link-local "			"address on %s", dev);		return;	}	dh6s->dh6sol_relayaddr = myaddr;	/*	 * Also places the number of bits of that make up the subnet prefix	 * for this address in the ``prefix-len'' field of the Solicit.	 * XXX: we blindly assume the length is 64 for now...	 */	cp_plen = (u_char *)&dh6s->dh6sol_plen_id;	plen = 64;		/* XXX */	*cp_plen &= 0x01; /* clear prefix-len for safety */	*cp_plen |= ((plen & 0xff) << 1);	/* set the source address and the outgoing interface */	memset(spktinfo, 0, sizeof(*spktinfo));	spktinfo->ipi6_addr = myaddr;	if ((spktinfo->ipi6_ifindex = if_nametoindex(dev)) == 0) {		/* this must not occur, so we might have to assert here */		dprintf(LOG_WARNING,			"relay6_react_solicit: invlalid interface: %s", dev);		return;	}	/* forward the solictation to servers */	smh.msg_name = (caddr_t)&sa6_all_servers;	smh.msg_namelen = sizeof(sa6_all_servers);	iov[0].iov_base = buf;	iov[0].iov_len = siz;	smh.msg_iov = iov;	smh.msg_iovlen = 1;	if (sendmsg(ssock, &smh, 0) != siz)		dprintf(LOG_WARNING, "relay6_react_solicit: sendmsg failed "			"(ifid = %d, src = %s): %s",			spktinfo->ipi6_ifindex,			in6addr2str(&spktinfo->ipi6_addr, 0), strerror(errno));}static voidrelay6_react_advert(buf, siz, dev)	char *buf, *dev;	size_t siz;{	struct dhcp6_advert *dh6a;	struct sockaddr_in6 sa6_relay;	const char *sdev;	dprintf(LOG_DEBUG, "relay6_react_advert");	if (siz < sizeof(*dh6a)) {		dprintf(LOG_INFO,			"relay6_react_advert: short packet (size = %d)", siz);		return;	}	dh6a = (struct dhcp6_advert *)buf;	memset(&sa6_relay, 0, sizeof(sa6_relay));	sa6_relay.sin6_family = AF_INET6;	sa6_relay.sin6_len = sizeof(sa6_relay);	sa6_relay.sin6_addr = dh6a->dh6adv_relayaddr;	sa6_relay.sin6_scope_id = in6_addrscopebyif(&dh6a->dh6adv_relayaddr,						    dev);	if (!IN6_IS_ADDR_LINKLOCAL(&dh6a->dh6adv_cliaddr)) {		dprintf(LOG_INFO,			"relay6_react_advert: client address (%s) is not "			"link-local", in6addr2str(&dh6a->dh6adv_cliaddr, 0));		return;	}	/*	 * Note that sdev is necessarily equal to dev, if we take the weak	 * host model.	 */	if ((sdev = getdev(&sa6_relay)) == NULL) {		dprintf(LOG_WARNING,			"relay6_react_advert: can't detect interface from %s",			addr2str((struct sockaddr *)&sa6_relay));		return;	}	relay6_forward_response(buf, siz, &dh6a->dh6adv_cliaddr, sdev);}static voidrelay6_forward_response(buf, siz, cliaddr, dev)	char *buf;	size_t siz;	struct in6_addr *cliaddr;	const char *dev;{	static struct iovec iov[2];	dprintf(LOG_DEBUG, "relay6_forward_response");	sa6_client.sin6_addr = *cliaddr;	smh.msg_name = (caddr_t)&sa6_client;	smh.msg_namelen = sizeof(sa6_client);	iov[0].iov_base = buf;	iov[0].iov_len = siz;	smh.msg_iov = iov;	smh.msg_iovlen = 1;	memset(spktinfo, 0, sizeof(*spktinfo));	/* set the outgoing interface */	if ((spktinfo->ipi6_ifindex = if_nametoindex(dev)) == 0) {		/* this must not occur, so we might have to assert here */		dprintf(LOG_ERR,			"relay6_forward_response: invlalid interface: %s", dev);		return;	}	if (sendmsg(ssock, &smh, 0) != siz)		dprintf(LOG_WARNING,			"relay6_forward_response: sendmsg failed on %s :%s",			dev, strerror(errno));}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -