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