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