1*df69c215Sderaadt /* $OpenBSD: kmroute.c,v 1.3 2019/06/28 13:32:47 deraadt Exp $ */
2978e5cffSnorby
3978e5cffSnorby /*
4978e5cffSnorby * Copyright (c) 2005, 2006 Esben Norby <norby@openbsd.org>
5978e5cffSnorby *
6978e5cffSnorby * Permission to use, copy, modify, and distribute this software for any
7978e5cffSnorby * purpose with or without fee is hereby granted, provided that the above
8978e5cffSnorby * copyright notice and this permission notice appear in all copies.
9978e5cffSnorby *
10978e5cffSnorby * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11978e5cffSnorby * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12978e5cffSnorby * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13978e5cffSnorby * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14978e5cffSnorby * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15978e5cffSnorby * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16978e5cffSnorby * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17978e5cffSnorby */
18978e5cffSnorby
19978e5cffSnorby #include <sys/types.h>
20978e5cffSnorby #include <sys/socket.h>
21978e5cffSnorby #include <netinet/in.h>
22978e5cffSnorby #include <arpa/inet.h>
23978e5cffSnorby #include <netinet/ip_mroute.h>
24978e5cffSnorby
25978e5cffSnorby #include <err.h>
26978e5cffSnorby #include <errno.h>
27978e5cffSnorby #include <stdlib.h>
28978e5cffSnorby #include <string.h>
29978e5cffSnorby
30978e5cffSnorby #include "igmp.h"
31978e5cffSnorby #include "dvmrpd.h"
32978e5cffSnorby #include "dvmrp.h"
33978e5cffSnorby #include "dvmrpe.h"
34978e5cffSnorby #include "log.h"
35978e5cffSnorby
36978e5cffSnorby extern struct dvmrpd_conf *conf;
37978e5cffSnorby char *mroute_ptr; /* packet buffer */
38978e5cffSnorby
39978e5cffSnorby void main_imsg_compose_rde(int, pid_t, void *, u_int16_t);
40978e5cffSnorby
41978e5cffSnorby int
kmr_init(int fd)42978e5cffSnorby kmr_init(int fd)
43978e5cffSnorby {
44978e5cffSnorby struct iface *iface;
45978e5cffSnorby struct route_report rr;
46978e5cffSnorby
47978e5cffSnorby LIST_FOREACH(iface, &conf->iface_list, entry) {
48978e5cffSnorby log_debug("kmr_init: interface %s", iface->name);
49978e5cffSnorby
50978e5cffSnorby rr.net.s_addr = iface->addr.s_addr & iface->mask.s_addr;
51978e5cffSnorby rr.mask = iface->mask;
52978e5cffSnorby rr.nexthop.s_addr = 0;
53978e5cffSnorby rr.metric = iface->metric;
54978e5cffSnorby rr.ifindex = iface->ifindex;
55978e5cffSnorby main_imsg_compose_rde(IMSG_ROUTE_REPORT, -1, &rr, sizeof(rr));
56978e5cffSnorby
57978e5cffSnorby mrt_add_vif(conf->mroute_socket, iface);
58978e5cffSnorby }
59978e5cffSnorby
60e39620e5Snicm if ((mroute_ptr = calloc(1, IBUF_READ_SIZE)) == NULL)
61978e5cffSnorby fatal("kmr_init");
62978e5cffSnorby
63978e5cffSnorby return (0);
64978e5cffSnorby }
65978e5cffSnorby
66978e5cffSnorby void
kmr_shutdown(void)67978e5cffSnorby kmr_shutdown(void)
68978e5cffSnorby {
69978e5cffSnorby struct iface *iface;
70978e5cffSnorby
71978e5cffSnorby kmr_mfc_decouple();
72978e5cffSnorby kmroute_clear();
73978e5cffSnorby
74978e5cffSnorby LIST_FOREACH(iface, &conf->iface_list, entry) {
75978e5cffSnorby log_debug("kmr_shutdown: interface %s", iface->name);
76978e5cffSnorby
77978e5cffSnorby mrt_del_vif(conf->mroute_socket, iface);
78978e5cffSnorby }
79978e5cffSnorby
80978e5cffSnorby free(mroute_ptr);
81978e5cffSnorby }
82978e5cffSnorby
83978e5cffSnorby void
kmr_recv_msg(int fd,short event,void * bula)84978e5cffSnorby kmr_recv_msg(int fd, short event, void *bula)
85978e5cffSnorby {
86978e5cffSnorby struct mfc mfc;
87978e5cffSnorby struct igmpmsg kernel_msg;
88978e5cffSnorby char *buf;
89978e5cffSnorby ssize_t r;
90978e5cffSnorby
91978e5cffSnorby if (event != EV_READ)
92978e5cffSnorby return;
93978e5cffSnorby
94978e5cffSnorby /* setup buffer */
95978e5cffSnorby buf = mroute_ptr;
96978e5cffSnorby
97e39620e5Snicm if ((r = recvfrom(fd, buf, IBUF_READ_SIZE, 0, NULL, NULL)) == -1) {
98978e5cffSnorby if (errno != EAGAIN && errno != EINTR)
99978e5cffSnorby log_debug("kmr_recv_msg: error receiving packet");
100978e5cffSnorby return;
101978e5cffSnorby }
102978e5cffSnorby
103978e5cffSnorby memcpy(&kernel_msg, buf, sizeof(kernel_msg));
104978e5cffSnorby
105978e5cffSnorby /* we are only interested in kernel messages */
106978e5cffSnorby if (kernel_msg.im_mbz != 0)
107978e5cffSnorby return;
108978e5cffSnorby
109978e5cffSnorby switch (kernel_msg.im_msgtype) {
110978e5cffSnorby case IGMPMSG_NOCACHE:
111978e5cffSnorby /* verify that dst is a multicast group */
112978e5cffSnorby if (!IN_MULTICAST(ntohl(kernel_msg.im_dst.s_addr))) {
113978e5cffSnorby log_debug("kmr_recv_msg: kernel providing garbage!");
114978e5cffSnorby return;
115978e5cffSnorby }
116978e5cffSnorby
117978e5cffSnorby /* send MFC entry to RDE */
118978e5cffSnorby mfc.origin = kernel_msg.im_src;
119978e5cffSnorby mfc.group = kernel_msg.im_dst;
120978e5cffSnorby mfc.ifindex = kernel_msg.im_vif;
121978e5cffSnorby main_imsg_compose_rde(IMSG_MFC_ADD, 0, &mfc, sizeof(mfc));
122978e5cffSnorby break;
123978e5cffSnorby case IGMPMSG_WRONGVIF:
124978e5cffSnorby case IGMPMSG_WHOLEPKT:
125978e5cffSnorby case IGMPMSG_BW_UPCALL:
126978e5cffSnorby default:
127978e5cffSnorby log_debug("kmr_recv_msg: unhandled msg type %d!",
128978e5cffSnorby kernel_msg.im_msgtype);
129978e5cffSnorby }
130978e5cffSnorby }
131978e5cffSnorby
132978e5cffSnorby void
kmr_mfc_couple(void)133978e5cffSnorby kmr_mfc_couple(void)
134978e5cffSnorby {
135978e5cffSnorby log_info("kernel multicast forwarding cache coupled");
136978e5cffSnorby }
137978e5cffSnorby
138978e5cffSnorby void
kmr_mfc_decouple(void)139978e5cffSnorby kmr_mfc_decouple(void)
140978e5cffSnorby {
141978e5cffSnorby log_info("kernel multicast forwarding cache decoupled");
142978e5cffSnorby }
143978e5cffSnorby
144978e5cffSnorby void
kmroute_clear(void)145978e5cffSnorby kmroute_clear(void)
146978e5cffSnorby {
147978e5cffSnorby
148978e5cffSnorby }
149978e5cffSnorby
150978e5cffSnorby int
mrt_init(int fd)151978e5cffSnorby mrt_init(int fd)
152978e5cffSnorby {
153978e5cffSnorby int flag = 1;
154978e5cffSnorby
155978e5cffSnorby if (setsockopt(fd, IPPROTO_IP, MRT_INIT, &flag,
156*df69c215Sderaadt sizeof(flag)) == -1) {
157978e5cffSnorby log_warn("mrt_init: error setting MRT_INIT");
158978e5cffSnorby return (-1);
159978e5cffSnorby }
160978e5cffSnorby
161978e5cffSnorby return (0);
162978e5cffSnorby }
163978e5cffSnorby
164978e5cffSnorby int
mrt_done(int fd)165978e5cffSnorby mrt_done(int fd)
166978e5cffSnorby {
167978e5cffSnorby int flag = 0;
168978e5cffSnorby
169978e5cffSnorby if (setsockopt(fd, IPPROTO_IP, MRT_DONE, &flag,
170*df69c215Sderaadt sizeof(flag)) == -1) {
171978e5cffSnorby log_warn("mrt_done: error setting MRT_DONE");
172978e5cffSnorby return (-1);
173978e5cffSnorby }
174978e5cffSnorby
175978e5cffSnorby return (0);
176978e5cffSnorby }
177978e5cffSnorby
178978e5cffSnorby int
mrt_add_vif(int fd,struct iface * iface)179978e5cffSnorby mrt_add_vif(int fd, struct iface *iface)
180978e5cffSnorby {
181978e5cffSnorby struct vifctl vc;
182978e5cffSnorby
183978e5cffSnorby vc.vifc_vifi = iface->ifindex;
184978e5cffSnorby vc.vifc_flags = 0;
185978e5cffSnorby vc.vifc_threshold = 1;
186978e5cffSnorby vc.vifc_rate_limit = 0;
187978e5cffSnorby vc.vifc_lcl_addr.s_addr = iface->addr.s_addr;
188978e5cffSnorby vc.vifc_rmt_addr.s_addr = 0;
189978e5cffSnorby
190978e5cffSnorby if (setsockopt(fd, IPPROTO_IP, MRT_ADD_VIF, &vc,
191*df69c215Sderaadt sizeof(vc)) == -1) {
192978e5cffSnorby log_warn("mrt_add_vif: error adding VIF");
193978e5cffSnorby return (-1);
194978e5cffSnorby }
195978e5cffSnorby
196978e5cffSnorby return (0);
197978e5cffSnorby }
198978e5cffSnorby
199978e5cffSnorby void
mrt_del_vif(int fd,struct iface * iface)200978e5cffSnorby mrt_del_vif(int fd, struct iface *iface)
201978e5cffSnorby {
202978e5cffSnorby vifi_t vifi;
203978e5cffSnorby
204978e5cffSnorby vifi = iface->ifindex;
205978e5cffSnorby
206978e5cffSnorby if (setsockopt(fd, IPPROTO_IP, MRT_DEL_VIF, &vifi,
207*df69c215Sderaadt sizeof(vifi)) == -1)
208978e5cffSnorby log_warn("mrt_del_vif: error deleting VIF");
209978e5cffSnorby }
210978e5cffSnorby
211978e5cffSnorby int
mrt_add_mfc(int fd,struct mfc * mfc)212978e5cffSnorby mrt_add_mfc(int fd, struct mfc *mfc)
213978e5cffSnorby {
214978e5cffSnorby struct mfcctl mc;
215978e5cffSnorby int i;
216978e5cffSnorby
217978e5cffSnorby log_debug("mrt_add_mfc: interface %d, group %s", mfc->ifindex,
218978e5cffSnorby inet_ntoa(mfc->group));
219978e5cffSnorby
220978e5cffSnorby mc.mfcc_origin = mfc->origin;
221978e5cffSnorby mc.mfcc_mcastgrp = mfc->group;
222978e5cffSnorby mc.mfcc_parent = mfc->ifindex;
223978e5cffSnorby
224978e5cffSnorby for (i = 0; i < MAXVIFS; i++) {
225978e5cffSnorby mc.mfcc_ttls[i] = mfc->ttls[i];
226978e5cffSnorby }
227978e5cffSnorby
228978e5cffSnorby if (setsockopt(fd, IPPROTO_IP, MRT_ADD_MFC, &mc, sizeof(mc))
229*df69c215Sderaadt == -1) {
230978e5cffSnorby log_warnx("mrt_add_mfc: error adding group %s to interface %d",
231978e5cffSnorby inet_ntoa(mfc->group), mfc->ifindex);
232978e5cffSnorby return (-1);
233978e5cffSnorby }
234978e5cffSnorby
235978e5cffSnorby return (0);
236978e5cffSnorby }
237978e5cffSnorby
238978e5cffSnorby int
mrt_del_mfc(int fd,struct mfc * mfc)239978e5cffSnorby mrt_del_mfc(int fd, struct mfc *mfc)
240978e5cffSnorby {
241978e5cffSnorby struct mfcctl mc;
242978e5cffSnorby
243978e5cffSnorby log_debug("mrt_del_mfc: group %s", inet_ntoa(mfc->group));
244978e5cffSnorby
245978e5cffSnorby mc.mfcc_origin = mfc->origin;
246978e5cffSnorby mc.mfcc_mcastgrp = mfc->group;
247978e5cffSnorby
248978e5cffSnorby if (setsockopt(fd, IPPROTO_IP, MRT_DEL_MFC, &mc, sizeof(mc))
249*df69c215Sderaadt == -1) {
250978e5cffSnorby log_warnx("mrt_del_mfc: error deleting group %s ",
251978e5cffSnorby inet_ntoa(mfc->group));
252978e5cffSnorby return (-1);
253978e5cffSnorby }
254978e5cffSnorby
255978e5cffSnorby return (0);
256978e5cffSnorby }
257