xref: /openbsd/usr.sbin/dvmrpd/kmroute.c (revision df69c215)
1 /*	$OpenBSD: kmroute.c,v 1.3 2019/06/28 13:32:47 deraadt Exp $ */
2 
3 /*
4  * Copyright (c) 2005, 2006 Esben Norby <norby@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <netinet/ip_mroute.h>
24 
25 #include <err.h>
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "igmp.h"
31 #include "dvmrpd.h"
32 #include "dvmrp.h"
33 #include "dvmrpe.h"
34 #include "log.h"
35 
36 extern struct dvmrpd_conf	*conf;
37 char				*mroute_ptr;	/* packet buffer */
38 
39 void	main_imsg_compose_rde(int, pid_t, void *, u_int16_t);
40 
41 int
kmr_init(int fd)42 kmr_init(int fd)
43 {
44 	struct iface		*iface;
45 	struct route_report	 rr;
46 
47 	LIST_FOREACH(iface, &conf->iface_list, entry) {
48 		log_debug("kmr_init: interface %s", iface->name);
49 
50 		rr.net.s_addr = iface->addr.s_addr & iface->mask.s_addr;
51 		rr.mask = iface->mask;
52 		rr.nexthop.s_addr = 0;
53 		rr.metric = iface->metric;
54 		rr.ifindex = iface->ifindex;
55 		main_imsg_compose_rde(IMSG_ROUTE_REPORT, -1, &rr, sizeof(rr));
56 
57 		mrt_add_vif(conf->mroute_socket, iface);
58 	}
59 
60 	if ((mroute_ptr = calloc(1, IBUF_READ_SIZE)) == NULL)
61 		fatal("kmr_init");
62 
63 	return (0);
64 }
65 
66 void
kmr_shutdown(void)67 kmr_shutdown(void)
68 {
69 	struct iface		*iface;
70 
71 	kmr_mfc_decouple();
72 	kmroute_clear();
73 
74 	LIST_FOREACH(iface, &conf->iface_list, entry) {
75 		log_debug("kmr_shutdown: interface %s", iface->name);
76 
77 		mrt_del_vif(conf->mroute_socket, iface);
78 	}
79 
80 	free(mroute_ptr);
81 }
82 
83 void
kmr_recv_msg(int fd,short event,void * bula)84 kmr_recv_msg(int fd, short event, void *bula)
85 {
86 	struct mfc		 mfc;
87 	struct igmpmsg		 kernel_msg;
88 	char			*buf;
89 	ssize_t			 r;
90 
91 	if (event != EV_READ)
92 		return;
93 
94 	/* setup buffer */
95 	buf = mroute_ptr;
96 
97 	if ((r = recvfrom(fd, buf, IBUF_READ_SIZE, 0, NULL, NULL)) == -1) {
98 		if (errno != EAGAIN && errno != EINTR)
99 			log_debug("kmr_recv_msg: error receiving packet");
100 		return;
101 	}
102 
103 	memcpy(&kernel_msg, buf, sizeof(kernel_msg));
104 
105 	/* we are only interested in kernel messages */
106 	if (kernel_msg.im_mbz != 0)
107 		return;
108 
109 	switch (kernel_msg.im_msgtype) {
110 	case IGMPMSG_NOCACHE:
111 		/* verify that dst is a multicast group */
112 		if (!IN_MULTICAST(ntohl(kernel_msg.im_dst.s_addr))) {
113 			log_debug("kmr_recv_msg: kernel providing garbage!");
114 			return;
115 		}
116 
117 		/* send MFC entry to RDE */
118 		mfc.origin = kernel_msg.im_src;
119 		mfc.group = kernel_msg.im_dst;
120 		mfc.ifindex = kernel_msg.im_vif;
121 		main_imsg_compose_rde(IMSG_MFC_ADD, 0, &mfc, sizeof(mfc));
122 		break;
123 	case IGMPMSG_WRONGVIF:
124 	case IGMPMSG_WHOLEPKT:
125 	case IGMPMSG_BW_UPCALL:
126 	default:
127 		log_debug("kmr_recv_msg: unhandled msg type %d!",
128 		    kernel_msg.im_msgtype);
129 	}
130 }
131 
132 void
kmr_mfc_couple(void)133 kmr_mfc_couple(void)
134 {
135 	log_info("kernel multicast forwarding cache coupled");
136 }
137 
138 void
kmr_mfc_decouple(void)139 kmr_mfc_decouple(void)
140 {
141 	log_info("kernel multicast forwarding cache decoupled");
142 }
143 
144 void
kmroute_clear(void)145 kmroute_clear(void)
146 {
147 
148 }
149 
150 int
mrt_init(int fd)151 mrt_init(int fd)
152 {
153 	int	flag = 1;
154 
155 	if (setsockopt(fd, IPPROTO_IP, MRT_INIT, &flag,
156 	    sizeof(flag)) == -1) {
157 		log_warn("mrt_init: error setting MRT_INIT");
158 		return (-1);
159 	}
160 
161 	return (0);
162 }
163 
164 int
mrt_done(int fd)165 mrt_done(int fd)
166 {
167 	int	flag = 0;
168 
169 	if (setsockopt(fd, IPPROTO_IP, MRT_DONE, &flag,
170 	    sizeof(flag)) == -1) {
171 		log_warn("mrt_done: error setting MRT_DONE");
172 		return (-1);
173 	}
174 
175 	return (0);
176 }
177 
178 int
mrt_add_vif(int fd,struct iface * iface)179 mrt_add_vif(int fd, struct iface *iface)
180 {
181 	struct vifctl	vc;
182 
183 	vc.vifc_vifi            = iface->ifindex;
184 	vc.vifc_flags           = 0;
185 	vc.vifc_threshold       = 1;
186 	vc.vifc_rate_limit	= 0;
187 	vc.vifc_lcl_addr.s_addr = iface->addr.s_addr;
188 	vc.vifc_rmt_addr.s_addr = 0;
189 
190 	if (setsockopt(fd, IPPROTO_IP, MRT_ADD_VIF, &vc,
191 	    sizeof(vc)) == -1) {
192 		log_warn("mrt_add_vif: error adding VIF");
193 		return (-1);
194 	}
195 
196 	return (0);
197 }
198 
199 void
mrt_del_vif(int fd,struct iface * iface)200 mrt_del_vif(int fd, struct iface *iface)
201 {
202 	vifi_t	 vifi;
203 
204 	vifi = iface->ifindex;
205 
206 	if (setsockopt(fd, IPPROTO_IP, MRT_DEL_VIF, &vifi,
207 	    sizeof(vifi)) == -1)
208 		log_warn("mrt_del_vif: error deleting VIF");
209 }
210 
211 int
mrt_add_mfc(int fd,struct mfc * mfc)212 mrt_add_mfc(int fd, struct mfc *mfc)
213 {
214 	struct mfcctl	 mc;
215 	int		 i;
216 
217 	log_debug("mrt_add_mfc: interface %d, group %s", mfc->ifindex,
218 	    inet_ntoa(mfc->group));
219 
220 	mc.mfcc_origin = mfc->origin;
221 	mc.mfcc_mcastgrp = mfc->group;
222 	mc.mfcc_parent = mfc->ifindex;
223 
224 	for (i = 0; i < MAXVIFS; i++) {
225 		mc.mfcc_ttls[i] = mfc->ttls[i];
226 	}
227 
228 	if (setsockopt(fd, IPPROTO_IP, MRT_ADD_MFC, &mc, sizeof(mc))
229 	    == -1) {
230 		log_warnx("mrt_add_mfc: error adding group %s to interface %d",
231 		    inet_ntoa(mfc->group), mfc->ifindex);
232 		return (-1);
233 	}
234 
235 	return (0);
236 }
237 
238 int
mrt_del_mfc(int fd,struct mfc * mfc)239 mrt_del_mfc(int fd, struct mfc *mfc)
240 {
241 	struct mfcctl	 mc;
242 
243 	log_debug("mrt_del_mfc: group %s", inet_ntoa(mfc->group));
244 
245 	mc.mfcc_origin = mfc->origin;
246 	mc.mfcc_mcastgrp = mfc->group;
247 
248 	if (setsockopt(fd, IPPROTO_IP, MRT_DEL_MFC, &mc, sizeof(mc))
249 	    == -1) {
250 		log_warnx("mrt_del_mfc: error deleting group %s ",
251 		    inet_ntoa(mfc->group));
252 		return (-1);
253 	}
254 
255 	return (0);
256 }
257