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 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 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 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 133 kmr_mfc_couple(void) 134 { 135 log_info("kernel multicast forwarding cache coupled"); 136 } 137 138 void 139 kmr_mfc_decouple(void) 140 { 141 log_info("kernel multicast forwarding cache decoupled"); 142 } 143 144 void 145 kmroute_clear(void) 146 { 147 148 } 149 150 int 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 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 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 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 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 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