1 /* $OpenBSD: pfe_route.c,v 1.5 2011/05/19 08:56:49 reyk Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Reyk Floeter <reyk@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/queue.h> 21 #include <sys/socket.h> 22 23 #include <net/if.h> 24 #include <netinet/in.h> 25 #include <arpa/inet.h> 26 #include <net/route.h> 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <unistd.h> 31 #include <event.h> 32 #include <string.h> 33 #include <errno.h> 34 35 #include <openssl/ssl.h> 36 37 #include "relayd.h" 38 39 struct relay_rtmsg { 40 struct rt_msghdr rm_hdr; 41 union { 42 struct { 43 struct sockaddr_in rm_dst; 44 struct sockaddr_in rm_gateway; 45 struct sockaddr_in rm_netmask; 46 struct sockaddr_rtlabel rm_label; 47 } u4; 48 struct { 49 struct sockaddr_in6 rm_dst; 50 struct sockaddr_in6 rm_gateway; 51 struct sockaddr_in6 rm_netmask; 52 struct sockaddr_rtlabel rm_label; 53 } u6; 54 } rm_u; 55 }; 56 57 void 58 init_routes(struct relayd *env) 59 { 60 u_int rtfilter; 61 62 if (!(env->sc_flags & F_NEEDRT)) 63 return; 64 65 if ((env->sc_rtsock = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) 66 fatal("init_routes: failed to open routing socket"); 67 68 rtfilter = ROUTE_FILTER(0); 69 if (setsockopt(env->sc_rtsock, AF_ROUTE, ROUTE_MSGFILTER, 70 &rtfilter, sizeof(rtfilter)) == -1) 71 fatal("init_routes: ROUTE_MSGFILTER"); 72 } 73 74 void 75 sync_routes(struct relayd *env, struct router *rt) 76 { 77 struct netroute *nr; 78 struct host *host; 79 char buf[MAXHOSTNAMELEN]; 80 struct ctl_netroute crt; 81 82 if (!(env->sc_flags & F_NEEDRT)) 83 return; 84 85 TAILQ_FOREACH(nr, &rt->rt_netroutes, nr_entry) { 86 print_host(&nr->nr_conf.ss, buf, sizeof(buf)); 87 TAILQ_FOREACH(host, &rt->rt_gwtable->hosts, entry) { 88 if (host->up == HOST_UNKNOWN) 89 continue; 90 91 log_debug("%s: " 92 "router %s route %s/%d gateway %s %s priority %d", 93 __func__, 94 rt->rt_conf.name, buf, nr->nr_conf.prefixlen, 95 host->conf.name, 96 HOST_ISUP(host->up) ? "up" : "down", 97 host->conf.priority); 98 99 crt.up = host->up; 100 memcpy(&crt.nr, &nr->nr_conf, sizeof(nr->nr_conf)); 101 memcpy(&crt.host, &host->conf, sizeof(host->conf)); 102 memcpy(&crt.rt, &rt->rt_conf, sizeof(rt->rt_conf)); 103 104 proc_compose_imsg(env->sc_ps, PROC_PARENT, -1, 105 IMSG_RTMSG, -1, &crt, sizeof(crt)); 106 } 107 } 108 } 109 110 int 111 pfe_route(struct relayd *env, struct ctl_netroute *crt) 112 { 113 struct relay_rtmsg rm; 114 struct sockaddr_rtlabel sr; 115 struct sockaddr_storage *gw; 116 struct sockaddr_in *s4; 117 struct sockaddr_in6 *s6; 118 size_t len = 0; 119 char *gwname; 120 int i = 0; 121 122 gw = &crt->host.ss; 123 gwname = crt->host.name; 124 125 bzero(&rm, sizeof(rm)); 126 bzero(&sr, sizeof(sr)); 127 128 rm.rm_hdr.rtm_msglen = len; 129 rm.rm_hdr.rtm_version = RTM_VERSION; 130 rm.rm_hdr.rtm_type = HOST_ISUP(crt->up) ? RTM_ADD : RTM_DELETE; 131 rm.rm_hdr.rtm_flags = RTF_STATIC | RTF_GATEWAY | RTF_MPATH; 132 rm.rm_hdr.rtm_seq = env->sc_rtseq++; 133 rm.rm_hdr.rtm_addrs = RTA_DST | RTA_GATEWAY; 134 rm.rm_hdr.rtm_tableid = crt->rt.rtable; 135 rm.rm_hdr.rtm_priority = crt->host.priority; 136 137 if (strlen(crt->rt.label)) { 138 rm.rm_hdr.rtm_addrs |= RTA_LABEL; 139 sr.sr_len = sizeof(sr); 140 if (snprintf(sr.sr_label, sizeof(sr.sr_label), 141 "%s", crt->rt.label) == -1) 142 goto bad; 143 } 144 145 if (crt->nr.ss.ss_family == AF_INET) { 146 rm.rm_hdr.rtm_msglen = len = 147 sizeof(rm.rm_hdr) + sizeof(rm.rm_u.u4); 148 149 bcopy(&sr, &rm.rm_u.u4.rm_label, sizeof(sr)); 150 151 s4 = &rm.rm_u.u4.rm_dst; 152 s4->sin_family = AF_INET; 153 s4->sin_len = sizeof(rm.rm_u.u4.rm_dst); 154 s4->sin_addr.s_addr = 155 ((struct sockaddr_in *)&crt->nr.ss)->sin_addr.s_addr; 156 157 s4 = &rm.rm_u.u4.rm_gateway; 158 s4->sin_family = AF_INET; 159 s4->sin_len = sizeof(rm.rm_u.u4.rm_gateway); 160 s4->sin_addr.s_addr = 161 ((struct sockaddr_in *)gw)->sin_addr.s_addr; 162 163 rm.rm_hdr.rtm_addrs |= RTA_NETMASK; 164 s4 = &rm.rm_u.u4.rm_netmask; 165 s4->sin_family = AF_INET; 166 s4->sin_len = sizeof(rm.rm_u.u4.rm_netmask); 167 if (crt->nr.prefixlen) 168 s4->sin_addr.s_addr = 169 htonl(0xffffffff << (32 - crt->nr.prefixlen)); 170 else if (crt->nr.prefixlen < 0) 171 rm.rm_hdr.rtm_flags |= RTF_HOST; 172 } else if (crt->nr.ss.ss_family == AF_INET6) { 173 rm.rm_hdr.rtm_msglen = len = 174 sizeof(rm.rm_hdr) + sizeof(rm.rm_u.u6); 175 176 bcopy(&sr, &rm.rm_u.u6.rm_label, sizeof(sr)); 177 178 s6 = &rm.rm_u.u6.rm_dst; 179 bcopy(((struct sockaddr_in6 *)&crt->nr.ss), 180 s6, sizeof(*s6)); 181 s6->sin6_family = AF_INET6; 182 s6->sin6_len = sizeof(*s6); 183 184 s6 = &rm.rm_u.u6.rm_gateway; 185 bcopy(((struct sockaddr_in6 *)gw), s6, sizeof(*s6)); 186 s6->sin6_family = AF_INET6; 187 s6->sin6_len = sizeof(*s6); 188 189 rm.rm_hdr.rtm_addrs |= RTA_NETMASK; 190 s6 = &rm.rm_u.u6.rm_netmask; 191 s6->sin6_family = AF_INET6; 192 s6->sin6_len = sizeof(*s6); 193 if (crt->nr.prefixlen) { 194 for (i = 0; i < crt->nr.prefixlen / 8; i++) 195 s6->sin6_addr.s6_addr[i] = 0xff; 196 i = crt->nr.prefixlen % 8; 197 if (i) 198 s6->sin6_addr.s6_addr[crt->nr.prefixlen 199 / 8] = 0xff00 >> i; 200 } else if (crt->nr.prefixlen < 0) 201 rm.rm_hdr.rtm_flags |= RTF_HOST; 202 } else 203 fatal("pfe_route: invalid address family"); 204 205 retry: 206 if (write(env->sc_rtsock, &rm, len) == -1) { 207 switch (errno) { 208 case EEXIST: 209 case ESRCH: 210 if (rm.rm_hdr.rtm_type == RTM_ADD) { 211 rm.rm_hdr.rtm_type = RTM_CHANGE; 212 goto retry; 213 } else if (rm.rm_hdr.rtm_type == RTM_DELETE) { 214 /* Ignore */ 215 break; 216 } 217 /* FALLTHROUGH */ 218 default: 219 goto bad; 220 } 221 } 222 223 log_debug("%s: gateway %s %s", __func__, gwname, 224 HOST_ISUP(crt->up) ? "added" : "deleted"); 225 226 return (0); 227 228 bad: 229 log_debug("%s: failed to %s gateway %s: %d %s", __func__, 230 HOST_ISUP(crt->up) ? "add" : "delete", gwname, 231 errno, strerror(errno)); 232 233 return (-1); 234 } 235